231 |
231 |
232 return r; |
232 return r; |
233 } |
233 } |
234 |
234 |
235 |
235 |
236 void add_http_status_line(sbuf_t *out, pool_handle_t *pool, Request *rq) { |
236 void add_http_status_line(CxBuffer *out, pool_handle_t *pool, Request *rq) { |
237 sbuf_write(out, "HTTP/1.1 ", 9); |
237 cxBufferWrite("HTTP/1.1 ", 1, 9, out); |
238 |
238 |
239 char *status_code_str = pool_malloc(pool, 8); |
239 char status_code_str[8]; |
240 int sc_len = snprintf(status_code_str, 8, "%d ", rq->status_num); |
240 int sc_len = snprintf(status_code_str, 8, "%d ", rq->status_num); |
241 sbuf_write(out, status_code_str, sc_len); |
241 cxBufferWrite(status_code_str, 1, sc_len, out); |
242 |
242 |
243 char *scmsg = pblock_findkeyval(pb_key_status, rq->srvhdrs); |
243 char *scmsg = pblock_findkeyval(pb_key_status, rq->srvhdrs); |
244 if(scmsg == NULL) { |
244 if(scmsg == NULL) { |
245 scmsg = "OK"; |
245 scmsg = "OK"; |
246 } |
246 } |
247 sbuf_write(out, scmsg, strlen(scmsg)); |
247 cxBufferWrite(scmsg, 1, strlen(scmsg), out); |
248 |
248 |
249 sbuf_write(out, "\r\n", 2); |
249 cxBufferWrite("\r\n", 1, 2, out); |
250 } |
250 } |
251 |
251 |
252 void add_http_response_header(sbuf_t *out, Request *rq) { |
252 void add_http_response_header(CxBuffer *out, Request *rq) { |
253 pblock *h = rq->srvhdrs; |
253 pblock *h = rq->srvhdrs; |
254 pb_entry *p; |
254 pb_entry *p; |
255 |
255 |
256 for(int i=0;i<h->hsize;i++) { |
256 for(int i=0;i<h->hsize;i++) { |
257 p = h->ht[i]; |
257 p = h->ht[i]; |
273 if(name[0] > 90) { |
273 if(name[0] > 90) { |
274 /* |
274 /* |
275 * make first char uppercase and write the remaining chars |
275 * make first char uppercase and write the remaining chars |
276 * unmodified to the buffer |
276 * unmodified to the buffer |
277 */ |
277 */ |
278 sbuf_put(out, name[0]-32); |
278 cxBufferPut(out, name[0]-32); |
279 if(name_len > 1) { |
279 if(name_len > 1) { |
280 sbuf_write(out, name+1, name_len-1); |
280 cxBufferWrite(name+1, 1, name_len-1, out); |
281 } |
281 } |
282 } else { |
282 } else { |
283 // first char is already uppercase so just write the name |
283 // first char is already uppercase so just write the name |
284 sbuf_write(out, name, name_len); |
284 cxBufferWrite(name, 1, name_len, out); |
285 } |
285 } |
286 |
286 |
287 sbuf_write(out, ": ", 2); |
287 cxBufferWrite(": ", 1, 2, out); |
288 sbuf_write(out, value, strlen(value)); |
288 cxBufferWrite(value, 1, strlen(value), out); |
289 sbuf_write(out, "\r\n", 2); |
289 cxBufferWrite("\r\n", 1, 2, out); |
290 |
290 |
291 p = p->next; |
291 p = p->next; |
292 } |
292 } |
293 } |
293 } |
294 } |
294 } |
295 |
295 |
296 int http_start_response(Session *sn, Request *rq) { |
296 struct HttpResponseWriter { |
297 Connection *conn = ((NSAPISession*)sn)->connection; |
297 Session *sn; |
298 |
298 Request *rq; |
|
299 CxBuffer buf; |
|
300 }; |
|
301 |
|
302 HttpResponseWriter *http_create_response(Session *sn, Request *rq) { |
|
303 HttpResponseWriter *writer = pool_malloc(sn->pool, sizeof(HttpResponseWriter)); |
|
304 if(!writer) { |
|
305 return NULL; |
|
306 } |
|
307 if(cxBufferInit(&writer->buf, NULL, 512, pool_allocator(sn->pool), CX_BUFFER_AUTO_EXTEND|CX_BUFFER_FREE_CONTENTS)) { |
|
308 pool_free(sn->pool, writer); |
|
309 return NULL; |
|
310 } |
|
311 writer->sn = sn; |
|
312 writer->rq = rq; |
|
313 |
299 if(rq->status_num == -1) { |
314 if(rq->status_num == -1) { |
300 protocol_status(sn, rq, 200, "OK"); |
315 protocol_status(sn, rq, 200, "OK"); |
301 } |
316 } |
302 |
317 |
303 // set socket blocking |
|
304 //int flags; |
|
305 //flags = fcntl(fd, F_GETFL, 0); |
|
306 //fcntl(fd, F_SETFL, flags ^ O_NONBLOCK); |
|
307 |
|
308 // output buffer |
|
309 sbuf_t *out = sbuf_new(512); |
|
310 |
|
311 // add the http status line to the output buffer |
318 // add the http status line to the output buffer |
312 add_http_status_line(out, sn->pool, rq); |
319 add_http_status_line(&writer->buf, sn->pool, rq); |
313 |
320 |
314 // add date header |
321 // add date header |
315 struct tm mtms; |
322 struct tm mtms; |
316 struct tm *mtm = system_gmtime(&rq->req_start, &mtms); |
323 struct tm *mtm = system_gmtime(&rq->req_start, &mtms); |
317 char date[HTTP_DATE_LEN + 1]; |
324 char date[HTTP_DATE_LEN + 1]; |
318 strftime(date, HTTP_DATE_LEN, HTTP_DATE_FMT, mtm); |
325 strftime(date, HTTP_DATE_LEN, HTTP_DATE_FMT, mtm); |
319 sbuf_write(out, "Date: ", 6); |
326 cxBufferWrite("Date: ", 1, 6, &writer->buf); |
320 sbuf_write(out, date, strlen(date)); |
327 cxBufferWrite(date, 1, strlen(date), &writer->buf); |
321 sbuf_write(out, "\r\n", 2); |
328 cxBufferWrite("\r\n", 1, 2, &writer->buf); |
322 |
329 |
323 // add server header |
330 // add server header |
324 sbuf_write(out, "Server: webserver\r\n", 19); |
331 cxBufferWrite("Server: webserver\r\n", 1, 19, &writer->buf); |
325 |
332 |
326 // check content length ans transfer encoding |
333 // check content length ans transfer encoding |
327 char *ctlen = pblock_findkeyval(pb_key_content_length, rq->srvhdrs); |
334 char *ctlen = pblock_findkeyval(pb_key_content_length, rq->srvhdrs); |
328 char *enc = pblock_findkeyval(pb_key_transfer_encoding, rq->srvhdrs); |
335 char *enc = pblock_findkeyval(pb_key_transfer_encoding, rq->srvhdrs); |
329 if(ctlen && enc) { |
336 if(ctlen && enc) { |
351 stream->chunked_enc = 1; |
358 stream->chunked_enc = 1; |
352 rq->rq_attr.chunked = 1; |
359 rq->rq_attr.chunked = 1; |
353 } |
360 } |
354 |
361 |
355 // add header from rq->srvhdrs |
362 // add header from rq->srvhdrs |
356 add_http_response_header(out, rq); |
363 add_http_response_header(&writer->buf, rq); |
357 |
364 |
358 // add connection header |
365 // add connection header |
359 if(rq->rq_attr.keep_alive) { |
366 if(rq->rq_attr.keep_alive) { |
360 sbuf_write(out, "Connection: keep-alive\r\n", 24); |
367 cxBufferWrite("Connection: keep-alive\r\n", 1, 24, &writer->buf); |
361 pblock_kvinsert(pb_key_connection, "keep-alive", 10, rq->srvhdrs); |
368 pblock_kvinsert(pb_key_connection, "keep-alive", 10, rq->srvhdrs); |
362 } else { |
369 } else { |
363 sbuf_write(out, "Connection: close\r\n", 19); |
370 cxBufferWrite("Connection: close\r\n", 1, 19, &writer->buf); |
364 pblock_kvinsert(pb_key_connection, "close", 5, rq->srvhdrs); |
371 pblock_kvinsert(pb_key_connection, "close", 5, rq->srvhdrs); |
365 } |
372 } |
366 |
|
367 |
373 |
368 // response header end |
374 // response header end |
369 sbuf_write(out, "\r\n", 2); |
375 cxBufferWrite("\r\n", 1, 2,& writer->buf); |
370 |
376 |
|
377 // reset pos (required for http_start_response_async) |
|
378 writer->buf.pos = 0; |
|
379 |
|
380 return writer; |
|
381 } |
|
382 |
|
383 int http_send_response(HttpResponseWriter *writer) { |
|
384 Connection *conn = ((NSAPISession*)writer->sn)->connection; |
|
385 CxBuffer *buf = &writer->buf; |
|
386 |
371 // flush buffer to the socket |
387 // flush buffer to the socket |
372 conn->write(conn, out->ptr, out->length); |
388 while(buf->pos < buf->size) { |
373 sbuf_free(out); |
389 int w = conn->write(conn, buf->space + buf->pos, buf->size - buf->pos); |
|
390 if(w <= 0) { |
|
391 if(conn->ssl) { |
|
392 if(conn->ssl_error == SSL_ERROR_WANT_WRITE) { |
|
393 return 1; |
|
394 } |
|
395 } else { |
|
396 if(errno == EWOULDBLOCK) { |
|
397 return 1; |
|
398 } |
|
399 } |
|
400 return -1; |
|
401 } |
|
402 buf->pos += w; |
|
403 } |
374 |
404 |
375 rq->senthdrs = 1; |
405 writer->rq->senthdrs = 1; |
|
406 |
|
407 cxBufferDestroy(buf); |
|
408 pool_free(writer->sn->pool, writer); |
376 |
409 |
377 return 0; |
410 return 0; |
|
411 } |
|
412 |
|
413 |
|
414 int http_start_response(Session *sn, Request *rq) { |
|
415 HttpResponseWriter *writer = http_create_response(sn, rq); |
|
416 if(!writer) { |
|
417 return 1; |
|
418 } |
|
419 |
|
420 return http_send_response(writer); |
378 } |
421 } |
379 |
422 |
380 int http_send_continue(Session *sn) { |
423 int http_send_continue(Session *sn) { |
381 NSAPISession *s = (NSAPISession*)sn; |
424 NSAPISession *s = (NSAPISession*)sn; |
382 cxstring msg = CX_STR("HTTP/1.1 100 Continue\r\n\r\n"); |
425 cxstring msg = CX_STR("HTTP/1.1 100 Continue\r\n\r\n"); |