src/server/proxy/httpclient.c

changeset 675
edacba8beedb
parent 674
6a031133a498
child 676
d43f1dd8b18e
equal deleted inserted replaced
674:6a031133a498 675:edacba8beedb
140 int http_client_add_request_header(HttpClient *client, cxmutstr name, cxmutstr value) { 140 int http_client_add_request_header(HttpClient *client, cxmutstr name, cxmutstr value) {
141 return header_array_add(client->request_headers, name, value); 141 return header_array_add(client->request_headers, name, value);
142 } 142 }
143 143
144 int http_client_add_request_header_copy(HttpClient *client, cxstring name, cxstring value) { 144 int http_client_add_request_header_copy(HttpClient *client, cxstring name, cxstring value) {
145 if(!client->mp) {
146 client->mp = cxMempoolCreate(64, CX_MEMPOOL_TYPE_PURE);
147 if(!client->mp) {
148 return 1;
149 }
150 }
151
145 cxmutstr n = cx_strdup_a(client->mp->allocator, name); 152 cxmutstr n = cx_strdup_a(client->mp->allocator, name);
146 cxmutstr v = cx_strdup_a(client->mp->allocator, value); 153 cxmutstr v = cx_strdup_a(client->mp->allocator, value);
147 154
148 int err = 1; 155 int err = 1;
149 if(n.ptr && v.ptr) { 156 if(n.ptr && v.ptr) {
152 if(err) { 159 if(err) {
153 cxFree(client->mp->allocator, n.ptr); 160 cxFree(client->mp->allocator, n.ptr);
154 cxFree(client->mp->allocator, v.ptr); 161 cxFree(client->mp->allocator, v.ptr);
155 } 162 }
156 return err; 163 return err;
164 }
165
166 int http_client_set_content_length(HttpClient *client, int64_t contentlength) {
167 client->req_content_length = contentlength;
168 char ctlen_buf[32];
169 size_t len = snprintf(ctlen_buf, 32, "%" PRId64, contentlength);
170 return http_client_add_request_header_copy(client, cx_str("content-length"), cx_strn(ctlen_buf, len));
171 }
172
173 int http_client_enable_chunked_transfer_encoding(HttpClient *client) {
174 client->req_content_length = -1;
175 return http_client_add_request_header(client, cx_mutstr("transfer-encoding"), cx_mutstr("chunked"));
157 } 176 }
158 177
159 int http_client_start(HttpClient *client) { 178 int http_client_start(HttpClient *client) {
160 int socketfd = socket(AF_INET, SOCK_STREAM, 0); 179 int socketfd = socket(AF_INET, SOCK_STREAM, 0);
161 if(socketfd < 0) { 180 if(socketfd < 0) {
190 return ret; 209 return ret;
191 } 210 }
192 211
193 static int create_req_buffer(HttpClient *client) { 212 static int create_req_buffer(HttpClient *client) {
194 CxBuffer buf; 213 CxBuffer buf;
195 if(cxBufferInit(&buf, cxDefaultAllocator, NULL, 1024, CX_BUFFER_AUTO_EXTEND)) { 214 if(cxBufferInit(&buf, cxDefaultAllocator, NULL, HTTP_CLIENT_BUFFER_SIZE, CX_BUFFER_AUTO_EXTEND)) {
196 return 1; 215 return 1;
197 } 216 }
198 217
199 if(client->method) { 218 if(client->method) {
200 cxBufferPutString(&buf, "GET "); 219 cxBufferPutString(&buf, "GET ");
214 } 233 }
215 hdr = hdr->next; 234 hdr = hdr->next;
216 } 235 }
217 cxBufferPutString(&buf, "\r\n"); 236 cxBufferPutString(&buf, "\r\n");
218 client->req_buffer = buf.space; 237 client->req_buffer = buf.space;
238 client->req_buffer_alloc = buf.capacity;
219 client->req_buffer_len = buf.size; 239 client->req_buffer_len = buf.size;
220 240
221 return 0; 241 return 0;
222 } 242 }
223 243
234 254
235 static int client_io(EventHandler *ev, Event *event) { 255 static int client_io(EventHandler *ev, Event *event) {
236 HttpClient *client = event->cookie; 256 HttpClient *client = event->cookie;
237 if(client->req_buffer_pos < client->req_buffer_len) { 257 if(client->req_buffer_pos < client->req_buffer_len) {
238 if(client_send_request(client)) { 258 if(client_send_request(client)) {
239 if(client->error) { 259 return client->error == 0;
240 return 0; // TODO: set error 260 }
261 }
262
263 // do we need to send a request body?
264 if(client->req_content_length != 0) {
265 while(!client->request_body_complete) {
266 ssize_t r = client->request_body_read(client, client->req_buffer, client->req_buffer_alloc, client->request_body_read_userdata);
267 if(r <= 0) {
268 if(r == HTTP_CLIENT_CALLBACK_WOULD_BLOCK) {
269 return 1;
270 } else if(r == 0) {
271 // EOF
272 client->request_body_complete = 1;
273 break;
274 } else {
275 // error
276 client->error = 1;
277 return 0;
278 }
241 } 279 }
242 return 1; 280 client->req_contentlength_pos += r;
243 } 281 client->req_buffer_pos = 0;
244 } 282 client->req_buffer_len = r;
283 if(client_send_request(client)) {
284 return client->error == 0;
285 }
286 }
287
288 if(client->req_content_length > 0 && client->req_content_length != client->req_contentlength_pos) {
289 // incomplete request body
290 client->error = 1;
291 return 0;
292 }
293 }
294
295
245 296
246 // writing complete, switch to read events 297 // writing complete, switch to read events
247 event->events = EVENT_POLLIN; 298 event->events = EVENT_POLLIN;
248 299
249 300
336 return 0; 387 return 0;
337 } 388 }
338 389
339 static int client_send_request(HttpClient *client) { 390 static int client_send_request(HttpClient *client) {
340 size_t nbytes = client->req_buffer_len - client->req_buffer_pos; 391 size_t nbytes = client->req_buffer_len - client->req_buffer_pos;
341 ssize_t w = write(client->socketfd, client->req_buffer + client->req_buffer_pos, nbytes); 392 ssize_t w;
393 while((w = write(client->socketfd, client->req_buffer + client->req_buffer_pos, nbytes)) > 0) {
394 client->req_buffer_pos += w;
395 nbytes = client->req_buffer_len - client->req_buffer_pos;
396 if(nbytes == 0) {
397 break;
398 }
399 }
400
342 if(w <= 0) { 401 if(w <= 0) {
343 if(errno != EAGAIN) { 402 if(errno != EAGAIN) {
344 // TODO: log correct host 403 // TODO: log correct host
345 log_ereport(LOG_VERBOSE, "http-client %s - %s: write failed: %s", "localhost", client->uri, strerror(errno)); 404 log_ereport(LOG_VERBOSE, "http-client %s - %s: write failed: %s", "localhost", client->uri, strerror(errno));
346 client->error = 1; 405 client->error = 1;
347 } 406 }
348 return 1; 407 return 1;
349 } 408 }
350
351 client->req_buffer_pos += w;
352 409
353 return client->req_buffer_pos < client->req_buffer_len; 410 return client->req_buffer_pos < client->req_buffer_len;
354 } 411 }
355 412
356 413

mercurial