http.c refactoring, headers

master
Nicolas Favre-Felix 14 years ago
parent 6026811c02
commit b30a2976ca

@ -13,7 +13,7 @@ acl_match_client(struct acl *a, struct http_client *client, in_addr_t *ip) {
/* check HTTP Basic Auth */
const char *auth;
auth = client->header_authorization.s;
auth = client->input_headers.authorization.s;
if(auth && a->http_basic_auth && strncasecmp(auth, "Basic ", 6) == 0) { /* sent auth */
if(strcmp(auth + 6, a->http_basic_auth) != 0) { /* wrong */
return 0;

@ -40,7 +40,7 @@ format_send_reply(struct cmd *cmd, const char *p, size_t sz, const char *content
if(cmd->started_responding == 0) {
const char *ct = cmd->mime?cmd->mime:content_type;
cmd->started_responding = 1;
http_set_header(&cmd->client->out_content_type, ct, strlen(ct));
http_set_header(&cmd->client->output_headers.content_type, ct, strlen(ct));
http_send_reply_start(cmd->client, 200, "OK");
}
http_send_reply_chunk(cmd->client, p, sz);
@ -48,16 +48,16 @@ format_send_reply(struct cmd *cmd, const char *p, size_t sz, const char *content
} else {
/* compute ETag */
char *etag = etag_new(p, sz);
const char *if_none_match = cmd->client->header_if_none_match.s;
const char *if_none_match = cmd->client->input_headers.if_none_match.s;
/* check If-None-Match */
if(if_none_match && strncmp(if_none_match, etag, cmd->client->header_if_none_match.sz) == 0) {
if(if_none_match && strncmp(if_none_match, etag, cmd->client->input_headers.if_none_match.sz) == 0) {
/* SAME! send 304. */
http_send_reply(cmd->client, 304, "Not Modified", NULL, 0);
} else {
const char *ct = cmd->mime?cmd->mime:content_type;
http_set_header(&cmd->client->out_content_type, ct, strlen(ct));
http_set_header(&cmd->client->out_etag, etag, strlen(etag));
http_set_header(&cmd->client->output_headers.content_type, ct, strlen(ct));
http_set_header(&cmd->client->output_headers.etag, etag, strlen(etag));
http_send_reply(cmd->client, 200, "OK", p, sz);
}

@ -71,20 +71,20 @@ http_client_cleanup(struct http_client *c) {
free(c->body.s);
memset(&c->body, 0, sizeof(str_t));
free(c->header_connection.s);
memset(&c->header_connection, 0, sizeof(str_t));
free(c->input_headers.connection.s);
memset(&c->input_headers.connection, 0, sizeof(str_t));
free(c->header_if_none_match.s);
memset(&c->header_if_none_match, 0, sizeof(str_t));
free(c->input_headers.if_none_match.s);
memset(&c->input_headers.if_none_match, 0, sizeof(str_t));
free(c->header_authorization.s);
memset(&c->header_authorization, 0, sizeof(str_t));
free(c->input_headers.authorization.s);
memset(&c->input_headers.authorization, 0, sizeof(str_t));
free(c->out_content_type.s);
memset(&c->out_content_type, 0, sizeof(str_t));
free(c->output_headers.content_type.s);
memset(&c->output_headers.content_type, 0, sizeof(str_t));
free(c->out_etag.s);
memset(&c->out_etag, 0, sizeof(str_t));
free(c->output_headers.etag.s);
memset(&c->output_headers.etag, 0, sizeof(str_t));
free(c->qs_type.s);
memset(&c->qs_type, 0, sizeof(str_t));
@ -131,10 +131,10 @@ http_client_keep_alive(struct http_client *c) {
} else if(c->parser.http_major == 1 && c->parser.http_minor == 0) {
disconnect = 1; /* HTTP 1.0: disconnect by default */
}
if(c->header_connection.s) {
if(strncasecmp(c->header_connection.s, "Keep-Alive", 10) == 0) {
if(c->input_headers.connection.s) {
if(strncasecmp(c->input_headers.connection.s, "Keep-Alive", 10) == 0) {
disconnect = 0;
} else if(strncasecmp(c->header_connection.s, "Close", 5) == 0) {
} else if(strncasecmp(c->input_headers.connection.s, "Close", 5) == 0) {
disconnect = 1;
}
}
@ -195,7 +195,6 @@ static int
http_crossdomain(struct http_client *c) {
struct http_response resp;
char content_length[10];
char out[] = "<?xml version=\"1.0\"?>\n"
"<!DOCTYPE cross-domain-policy SYSTEM \"http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd\">\n"
"<cross-domain-policy>\n"
@ -203,13 +202,10 @@ http_crossdomain(struct http_client *c) {
"</cross-domain-policy>\n";
http_response_init(c, &resp, 200, "OK");
http_response_set_header(&resp, "Content-Type", "application/xml");
sprintf(content_length, "%zd", sizeof(out)-1);
http_response_set_header(&resp, "Content-Length", content_length);
http_response_set_body(&resp, out, sizeof(out)-1);
http_response_send(&resp, c->fd);
http_response_write(&resp, c->fd);
http_client_reset(c);
return 0;
@ -231,7 +227,7 @@ http_options(struct http_client *c) {
/* Cross-Origin Resource Sharing, CORS. */
http_response_set_header(&resp, "Access-Control-Allow-Origin", "*");
http_response_send(&resp, c->fd);
http_response_write(&resp, c->fd);
http_client_reset(c);
return 0;
@ -291,8 +287,7 @@ http_send_reply(struct http_client *c, short code, const char *msg,
const char *body, size_t body_len) {
struct http_response resp;
char content_length[10];
const char *ct = c->out_content_type.s;
const char *ct = c->output_headers.content_type.s;
if(!ct) {
ct = "text/html";
}
@ -300,10 +295,6 @@ http_send_reply(struct http_client *c, short code, const char *msg,
/* respond */
http_response_init(c, &resp, code, msg);
sprintf(content_length, "%zd", body_len);
if(!c->sub) {
http_response_set_header(&resp, "Content-Length", content_length);
}
if(body_len) {
http_response_set_header(&resp, "Content-Type", ct);
}
@ -312,14 +303,14 @@ http_send_reply(struct http_client *c, short code, const char *msg,
http_response_set_header(&resp, "Transfer-Encoding", "chunked");
}
if(code == 200 && c->out_etag.s) {
http_response_set_header(&resp, "ETag", c->out_etag.s);
if(code == 200 && c->output_headers.etag.s) {
http_response_set_header(&resp, "ETag", c->output_headers.etag.s);
}
http_response_set_body(&resp, body, body_len);
/* flush response in the socket */
if(http_response_send(&resp, c->fd)) {
if(http_response_write(&resp, c->fd)) {
http_client_free(c);
} else {
if(c->sub) { /* don't free the client, but monitor fd. */
@ -392,17 +383,11 @@ http_on_header_value(http_parser *p, const char *at, size_t length) {
struct http_client *c = p->data;
if(strncmp("Connection", c->last_header_name.s, c->last_header_name.sz) == 0) {
c->header_connection.s = calloc(length+1, 1);
memcpy(c->header_connection.s, at, length);
c->header_connection.sz = length;
http_set_header(&c->input_headers.connection, at, length);
} else if(strncmp("If-None-Match", c->last_header_name.s, c->last_header_name.sz) == 0) {
c->header_if_none_match.s = calloc(length+1, 1);
memcpy(c->header_if_none_match.s, at, length);
c->header_if_none_match.sz = length;
http_set_header(&c->input_headers.if_none_match, at, length);
} else if(strncmp("Authorization", c->last_header_name.s, c->last_header_name.sz) == 0) {
c->header_authorization.s = calloc(length+1, 1);
memcpy(c->header_authorization.s, at, length);
c->header_authorization.sz = length;
http_set_header(&c->input_headers.authorization, at, length);
} else if(strncmp("Expect", c->last_header_name.s, c->last_header_name.sz) == 0) {
if(length == 12 && memcmp(at, "100-continue", length) == 0) {
/* support HTTP file upload */
@ -415,6 +400,7 @@ http_on_header_value(http_parser *p, const char *at, size_t length) {
c->last_header_name.s = NULL;
return 0;
}
/**
* Called when the query string is found
*/
@ -480,6 +466,7 @@ http_response_init(struct http_client *c, struct http_response *r, int code, con
void
http_response_set_header(struct http_response *r, const char *k, const char *v) {
int i, pos = r->header_count;
size_t sz;
char *s;
@ -487,11 +474,22 @@ http_response_set_header(struct http_response *r, const char *k, const char *v)
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;
for(i = 0; i < r->header_count; ++i) {
size_t klen = strlen(k);
if(strncmp(r->headers[i].s, k, klen) == 0 && r->headers[i].s[klen] == ':') {
pos = i;
free(r->headers[i].s);
break;
}
}
if(pos == r->header_count) {
r->headers = realloc(r->headers, sizeof(str_t)*(r->header_count + 1));
r->header_count++;
}
r->headers[pos].s = s;
r->headers[pos].sz = sz;
r->header_count++;
}
void
@ -502,7 +500,7 @@ http_response_set_body(struct http_response *r, const char *body, size_t body_le
}
int
http_response_send(struct http_response *r, int fd) {
http_response_write(struct http_response *r, int fd) {
char *s = NULL, *p;
size_t sz = 0;
@ -514,6 +512,14 @@ http_response_send(struct http_response *r, int fd) {
ret = sprintf(s, "HTTP/1.1 %d %s\r\n", r->code, r->msg);
p = s; // + ret - 3;
if(r->code == 200 && r->body) {
char content_length[10];
sprintf(content_length, "%zd", r->body_len);
http_response_set_header(r, "Content-Length", content_length);
http_response_set_header(r, "Content-Length", content_length);
http_response_set_header(r, "Content-Length", content_length);
}
for(i = 0; i < r->header_count; ++i) {
s = realloc(s, sz + r->headers[i].sz);
p = s + sz;

@ -27,18 +27,25 @@ struct http_client {
enum http_method verb;
str_t path;
str_t body;
str_t header_connection;
str_t header_if_none_match;
str_t header_authorization;
/* input headers from client */
struct {
str_t connection;
str_t if_none_match;
str_t authorization;
} input_headers;
/* response headers */
str_t out_content_type;
str_t out_etag;
struct input_headers {
str_t content_type;
str_t etag;
} output_headers;
/* query string */
str_t qs_type;
str_t qs_jsonp;
/* pub/sub */
struct subscription *sub;
/* private, used in HTTP parser */
@ -118,6 +125,6 @@ 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);
http_response_write(struct http_response *r, int fd);
#endif

@ -6,8 +6,6 @@
#include <sys/queue.h>
#include <event.h>
struct evhttp;
struct server {
struct conf *cfg;

Loading…
Cancel
Save