http.c (3164B)
1 #include "http.h" 2 #include "util.h" 3 #include "parse.h" 4 5 #include <stdio.h> 6 #include <assert.h> 7 8 9 void init_http_req(struct http_req *req) 10 { 11 memset(req, 0, sizeof(*req)); 12 init_errors(&req->errs); 13 } 14 15 static int parse_segment_with(struct parser *p, char **seg, char delim) 16 { 17 char c; 18 19 *seg = (char*)p->arena.p; 20 21 while (1) { 22 if (!pull_byte(&p->cur, (unsigned char*)&c)) 23 return 0; 24 25 if (c == delim) { 26 if (!push_byte(&p->arena, 0)) 27 return 0; 28 return 1; 29 } 30 31 if (!push_byte(&p->arena, c)) 32 return 0; 33 } 34 35 return 1; 36 } 37 38 static int parse_segment(struct parser *p, char **seg) 39 { 40 return parse_segment_with(p, seg, ' '); 41 } 42 43 static int parse_last_segment(struct parser *p, char **seg) 44 { 45 if (!parse_segment_with(p, seg, '\r')) 46 return 0; 47 48 consume_char(&p->cur, '\n'); 49 50 return 1; 51 } 52 53 static int parse_header_name(struct parser *p, char **name) 54 { 55 if (!parse_segment_with(p, name, ':')) 56 return 0; 57 58 return consume_char(&p->cur, ' '); 59 } 60 61 static int consume_crlf(struct cursor *cur) 62 { 63 return consume_char(cur, '\r') && consume_char(cur, '\n'); 64 } 65 66 static int parse_request_line(struct http_req *req, struct parser *p) 67 { 68 if (!parse_segment(p, &req->method)) 69 return 0; 70 71 if (!parse_segment(p, &req->path)) 72 return 0; 73 74 return parse_last_segment(p, &req->ver); 75 } 76 77 static int parse_header(struct http_header **prev, struct parser *p) 78 { 79 struct http_header next; 80 struct http_header *next_p; 81 next.next = NULL; 82 83 assert(prev); 84 assert(*prev == NULL || (*prev)->next == NULL); 85 86 if (!parse_header_name(p, &next.name)) 87 return 0; 88 89 if (!parse_last_segment(p, &next.value)) 90 return 0; 91 92 next_p = (struct http_header *)p->arena.p; 93 94 if (!push_data(&p->arena, (unsigned char*)&next, sizeof(next))) 95 return 0; 96 97 if (*prev == NULL) 98 *prev = next_p; 99 else 100 (*prev)->next = next_p; 101 102 return 1; 103 } 104 105 106 int parse_http_request(struct http_req *req, struct parser *p, int size) 107 { 108 struct http_header **header; 109 struct cursor back; 110 111 if (!parse_request_line(req, p)) 112 return 0; 113 114 header = &req->headers; 115 116 while (1) { 117 copy_cursor(&p->cur, &back); 118 if (!parse_header(header, p)) { 119 copy_cursor(&back, &p->cur); 120 break; 121 } 122 header = &(*header)->next; 123 } 124 125 if (!consume_crlf(&p->cur)) { 126 note_error(&req->errs, "pre-body crlf"); 127 return 0; 128 } 129 130 req->body = p->cur.p; 131 req->body_len = size - (p->cur.p - p->cur.start); 132 133 return 1; 134 } 135 136 void print_http_request(struct http_req *req) 137 { 138 struct http_header *header; 139 printf("%s %s %s\r\n", req->method, req->path, req->ver); 140 header = req->headers; 141 for (; header; header = header->next) { 142 printf("%s: %s\n", header->name, header->value); 143 } 144 } 145 146 int get_header(struct http_header *header, const char *match, 147 const char **result) 148 { 149 for (; header; header = header->next) { 150 if (stricmp(header->name, match)) { 151 *result = header->value; 152 return 1; 153 } 154 } 155 156 return 0; 157 } 158 159 void http_write_status(struct http_req *req, const char *status) 160 { 161 fprintf(req->client.socket_file, "HTTP/1.1 %s\r\n", status); 162 } 163 164 void http_write_header(struct http_req *req, const char *status) 165 { 166 http_write_status(req, status); 167 fprintf(req->client.socket_file, "Connection: close\r\n"); 168 fprintf(req->client.socket_file, "\r\n"); 169 } 170