| 250 event->fn = client_io; |
250 event->fn = client_io; |
| 251 |
251 |
| 252 return client_io(ev, event); |
252 return client_io(ev, event); |
| 253 } |
253 } |
| 254 |
254 |
| |
255 static int client_send_request_body(HttpClient *client) { |
| |
256 size_t rbody_readsize = client->req_buffer_alloc; |
| |
257 size_t rbody_buf_offset = 0; |
| |
258 if(client->req_content_length == -1) { |
| |
259 // chunked transfer encoding: |
| |
260 // don't fill req_buffer completely, reserve some space for |
| |
261 // a chunk header, that will be inserted at the beginning |
| |
262 rbody_readsize -= 16; |
| |
263 rbody_buf_offset = 16; |
| |
264 } |
| |
265 while(!client->request_body_complete) { |
| |
266 ssize_t r = client->request_body_read(client, client->req_buffer + rbody_buf_offset, rbody_readsize, 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 1; |
| |
278 } |
| |
279 } |
| |
280 |
| |
281 size_t startpos = 0; |
| |
282 if(client->req_content_length == -1) { |
| |
283 char chunkheader[16]; |
| |
284 int chunkheaderlen = snprintf(chunkheader, 16, "%zx\r\n", (size_t)r); |
| |
285 startpos = 16 - chunkheaderlen; |
| |
286 memcpy(client->req_buffer + startpos, chunkheader, chunkheaderlen); |
| |
287 } |
| |
288 |
| |
289 client->req_contentlength_pos += r; |
| |
290 client->req_buffer_pos = startpos; |
| |
291 client->req_buffer_len = r; |
| |
292 if(client_send_request(client)) { |
| |
293 return 1; |
| |
294 } |
| |
295 } |
| |
296 |
| |
297 if(client->req_content_length > 0 && client->req_content_length != client->req_contentlength_pos) { |
| |
298 // incomplete request body |
| |
299 client->error = 1; |
| |
300 return 1; |
| |
301 } |
| |
302 |
| |
303 return 0; |
| |
304 } |
| |
305 |
| 255 static int client_io(EventHandler *ev, Event *event) { |
306 static int client_io(EventHandler *ev, Event *event) { |
| 256 HttpClient *client = event->cookie; |
307 HttpClient *client = event->cookie; |
| 257 if(client->req_buffer_pos < client->req_buffer_len) { |
308 if(client->req_buffer_pos < client->req_buffer_len) { |
| 258 if(client_send_request(client)) { |
309 if(client_send_request(client)) { |
| 259 return client->error == 0; |
310 return client->error == 0; |
| 260 } |
311 } |
| 261 } |
312 } |
| 262 |
313 |
| 263 // do we need to send a request body? |
314 // do we need to send a request body? |
| 264 if(client->req_content_length != 0) { |
315 if(client->req_content_length != 0) { |
| 265 while(!client->request_body_complete) { |
316 if(client_send_request_body(client)) { |
| 266 ssize_t r = client->request_body_read(client, client->req_buffer, client->req_buffer_alloc, client->request_body_read_userdata); |
317 return client->error == 0; |
| 267 if(r <= 0) { |
318 } |
| 268 if(r == HTTP_CLIENT_CALLBACK_WOULD_BLOCK) { |
319 } |
| 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 } |
|
| 279 } |
|
| 280 client->req_contentlength_pos += r; |
|
| 281 client->req_buffer_pos = 0; |
|
| 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 |
|
| 296 |
320 |
| 297 // writing complete, switch to read events |
321 // writing complete, switch to read events |
| 298 event->events = EVENT_POLLIN; |
322 event->events = EVENT_POLLIN; |
| 299 |
323 |
| 300 |
324 |