src/server/daemon/protocol.c

changeset 432
7c9137f9e7f9
parent 415
d938228c382e
child 433
39fe86ae4db0
equal deleted inserted replaced
431:032b0ad35ee3 432:7c9137f9e7f9
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");

mercurial