| 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 "); |
| 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 |