From bfe22fdf2da93894767546754081addb2397b684 Mon Sep 17 00:00:00 2001 From: Nicolas Favre-Felix Date: Sat, 22 Jan 2011 17:23:28 +0100 Subject: [PATCH] Better HTTP response. --- http.c | 135 +++++++++++++++++++++++++++++++++++++++++++++------------ http.h | 27 +++++++++++- 2 files changed, 133 insertions(+), 29 deletions(-) diff --git a/http.c b/http.c index 435af05..d4f66a5 100644 --- a/http.c +++ b/http.c @@ -188,43 +188,44 @@ void http_send_reply(struct http_client *c, short code, const char *msg, const char *body, size_t body_len) { - char *out = NULL; - size_t sz = 0; - int ret = 0, ok; - + struct http_response resp; + char content_length[10]; const char *ct = c->out_content_type.s; if(!ct) { ct = "text/html"; } - while(1) { - ret = snprintf(out, sz, "HTTP/1.1 %d %s\r\n" - "Content-Type: %s\r\n" - "Content-Length: %zd\r\n" - "ETag: %s\r\n" - "Connection: %s\r\n" - "Server: Webdis\r\n" - "\r\n", code, msg, ct, body_len, - (c->out_etag.s ? c->out_etag.s : "\"\""), - (http_client_keep_alive(c) ? "Keep-Alive" : "Close") - ); - - if(!out) { /* first step: allocate space */ - sz = ret + body_len; - out = malloc(sz); - } else { /* second step: copy body and leave loop */ - if(body && body_len) memcpy(out + ret, body, body_len); - break; - } + /* respond */ + http_response_init(&resp, code, msg); + + http_response_set_header(&resp, "Server", "Webdis"); + if(!http_client_keep_alive(c)) { + http_response_set_header(&resp, "Connection", "Close"); + } else if(code == 200) { + http_response_set_header(&resp, "Connection", "Keep-Alive"); } - ok = write(c->fd, out, sz); - if(ok != (int)sz) { - http_client_free(c); + sprintf(content_length, "%zd", body_len); + http_response_set_header(&resp, "Content-Length", content_length); + if(body_len) { + http_response_set_header(&resp, "Content-Type", ct); } - free(out); - http_client_reset(c); + if(code == 200 && c->out_etag.s) { + http_response_set_header(&resp, "ETag", c->out_etag.s); + } + + http_response_set_body(&resp, body, body_len); + + if(http_response_send(&resp, c->fd)) { + http_client_free(c); + } else { + if(code == 200){ + http_client_reset(c); + } else { + http_client_free(c); + } + } } void @@ -265,3 +266,81 @@ http_on_header_value(http_parser *p, const char *at, size_t length) { } return 0; } + +/* HTTP Response */ +void +http_response_init(struct http_response *r, int code, const char *msg) { + + memset(r, 0, sizeof(struct http_response)); + r->code = code; + r->msg = msg; +} + +void +http_response_set_header(struct http_response *r, const char *k, const char *v) { + + size_t sz; + char *s; + + sz = strlen(k) + 2 + strlen(v) + 2; + s = calloc(sz + 1, 1); + sprintf(s, "%s: %s\r\n", k, v); + + r->headers = realloc(r->headers, sizeof(str_t)*(r->header_count + 1)); + r->headers[r->header_count].s = s; + r->headers[r->header_count].sz = sz; + + r->header_count++; +} + +void +http_response_set_body(struct http_response *r, const char *body, size_t body_len) { + + r->body = body; + r->body_len = body_len; +} + +int +http_response_send(struct http_response *r, int fd) { + + char *s = NULL, *p; + size_t sz = 0; + int i, ret; + + sz = sizeof("HTTP/1.x xxx ")-1 + strlen(r->msg) + 2; + s = calloc(sz + 1, 1); + + ret = sprintf(s, "HTTP/1.1 %d %s\r\n", r->code, r->msg); + p = s; // + ret - 3; + + for(i = 0; i < r->header_count; ++i) { + s = realloc(s, sz + r->headers[i].sz); + p = s + sz; + memcpy(p, r->headers[i].s, r->headers[i].sz); + + p += r->headers[i].sz; + sz += r->headers[i].sz; + } + + /* end of headers */ + s = realloc(s, sz + 2); + memcpy(s + sz, "\r\n", 2); + sz += 2; + + if(r->body && r->body_len) { + s = realloc(s, sz + r->body_len); + memcpy(s + sz, r->body, r->body_len); + sz += r->body_len; + } + /* + printf("sz=%zd, s=["); fflush(stdout); + write(1, s, sz); + printf("]\n"); + */ + + ret = write(fd, s, sz); + free(s); + + return ret == (int)sz ? 0 : 1; +} + diff --git a/http.h b/http.h index 7806040..3fabd4a 100644 --- a/http.h +++ b/http.h @@ -27,12 +27,12 @@ struct http_client { /* decoded http */ enum http_method verb; - str_t path; str_t body; str_t header_connection; str_t header_if_none_match; + /* response headers */ str_t out_content_type; str_t out_etag; @@ -40,6 +40,17 @@ struct http_client { str_t last_header_name; }; +struct http_response { + short code; + const char *msg; + + str_t *headers; + int header_count; + + const char *body; + size_t body_len; +}; + struct http_client * http_client_new(int fd, struct server *s); @@ -74,4 +85,18 @@ void http_send_reply(struct http_client *c, short code, const char *msg, const char *body, size_t body_len); +/* HTTP response */ +void +http_response_init(struct http_response *r, int code, const char *msg); + +void +http_response_set_header(struct http_response *r, const char *k, const char *v); + +void +http_response_set_body(struct http_response *r, const char *body, size_t body_len); + +int +http_response_send(struct http_response *r, int fd); + + #endif