Initial commit to the repository
[deb_shairplay.git] / src / http_request.c
1 #include <stdlib.h>
2 #include <string.h>
3 #include <assert.h>
4
5 #include "http_request.h"
6 #include "http_parser.h"
7
8 struct http_request_s {
9 http_parser parser;
10 http_parser_settings parser_settings;
11
12 const char *method;
13 char *url;
14
15 char **headers;
16 int headers_size;
17 int headers_index;
18
19 char *data;
20 int datalen;
21
22 int complete;
23 };
24
25 static int
26 on_url(http_parser *parser, const char *at, size_t length)
27 {
28 http_request_t *request = parser->data;
29 int urllen = request->url ? strlen(request->url) : 0;
30
31 request->url = realloc(request->url, urllen+length+1);
32 assert(request->url);
33
34 request->url[urllen] = '\0';
35 strncat(request->url, at, length);
36 return 0;
37 }
38
39 static int
40 on_header_field(http_parser *parser, const char *at, size_t length)
41 {
42 http_request_t *request = parser->data;
43
44 /* Check if our index is a value */
45 if (request->headers_index%2 == 1) {
46 request->headers_index++;
47 }
48
49 /* Allocate space for new field-value pair */
50 if (request->headers_index == request->headers_size) {
51 request->headers_size += 2;
52 request->headers = realloc(request->headers,
53 request->headers_size*sizeof(char*));
54 assert(request->headers);
55 request->headers[request->headers_index] = NULL;
56 request->headers[request->headers_index+1] = NULL;
57 }
58
59 /* Allocate space in the current header string */
60 if (request->headers[request->headers_index] == NULL) {
61 request->headers[request->headers_index] = calloc(1, length+1);
62 } else {
63 request->headers[request->headers_index] = realloc(
64 request->headers[request->headers_index],
65 strlen(request->headers[request->headers_index])+length+1
66 );
67 }
68 assert(request->headers[request->headers_index]);
69
70 strncat(request->headers[request->headers_index], at, length);
71 return 0;
72 }
73
74 static int
75 on_header_value(http_parser *parser, const char *at, size_t length)
76 {
77 http_request_t *request = parser->data;
78
79 /* Check if our index is a field */
80 if (request->headers_index%2 == 0) {
81 request->headers_index++;
82 }
83
84 /* Allocate space in the current header string */
85 if (request->headers[request->headers_index] == NULL) {
86 request->headers[request->headers_index] = calloc(1, length+1);
87 } else {
88 request->headers[request->headers_index] = realloc(
89 request->headers[request->headers_index],
90 strlen(request->headers[request->headers_index])+length+1
91 );
92 }
93 assert(request->headers[request->headers_index]);
94
95 strncat(request->headers[request->headers_index], at, length);
96 return 0;
97 }
98
99 static int
100 on_body(http_parser *parser, const char *at, size_t length)
101 {
102 http_request_t *request = parser->data;
103
104 request->data = realloc(request->data, request->datalen+length);
105 assert(request->data);
106
107 memcpy(request->data+request->datalen, at, length);
108 request->datalen += length;
109 return 0;
110 }
111
112 static int
113 on_message_complete(http_parser *parser)
114 {
115 http_request_t *request = parser->data;
116
117 request->method = http_method_str(request->parser.method);
118 request->complete = 1;
119 return 0;
120 }
121
122 http_request_t *
123 http_request_init(int numerichost)
124 {
125 http_request_t *request;
126
127 request = calloc(1, sizeof(http_request_t));
128 if (!request) {
129 return NULL;
130 }
131 http_parser_init(&request->parser, HTTP_REQUEST, !!numerichost);
132 request->parser.data = request;
133
134 request->parser_settings.on_url = &on_url;
135 request->parser_settings.on_header_field = &on_header_field;
136 request->parser_settings.on_header_value = &on_header_value;
137 request->parser_settings.on_body = &on_body;
138 request->parser_settings.on_message_complete = &on_message_complete;
139
140 return request;
141 }
142
143 void
144 http_request_destroy(http_request_t *request)
145 {
146 int i;
147
148 if (request) {
149 free(request->url);
150 for (i=0; i<request->headers_size; i++) {
151 free(request->headers[i]);
152 }
153 free(request->headers);
154 free(request->data);
155 free(request);
156 }
157 }
158
159 int
160 http_request_add_data(http_request_t *request, const char *data, int datalen)
161 {
162 int ret;
163
164 assert(request);
165
166 ret = http_parser_execute(&request->parser,
167 &request->parser_settings,
168 data, datalen);
169 return ret;
170 }
171
172 int
173 http_request_is_complete(http_request_t *request)
174 {
175 assert(request);
176 return request->complete;
177 }
178
179 int
180 http_request_has_error(http_request_t *request)
181 {
182 assert(request);
183 return (HTTP_PARSER_ERRNO(&request->parser) != HPE_OK);
184 }
185
186 const char *
187 http_request_get_error_name(http_request_t *request)
188 {
189 assert(request);
190 return http_errno_name(HTTP_PARSER_ERRNO(&request->parser));
191 }
192
193 const char *
194 http_request_get_error_description(http_request_t *request)
195 {
196 assert(request);
197 return http_errno_description(HTTP_PARSER_ERRNO(&request->parser));
198 }
199
200 const char *
201 http_request_get_method(http_request_t *request)
202 {
203 assert(request);
204 return request->method;
205 }
206
207 const char *
208 http_request_get_url(http_request_t *request)
209 {
210 assert(request);
211 return request->url;
212 }
213
214 const char *
215 http_request_get_header(http_request_t *request, const char *name)
216 {
217 int i;
218
219 assert(request);
220
221 for (i=0; i<request->headers_size; i+=2) {
222 if (!strcmp(request->headers[i], name)) {
223 return request->headers[i+1];
224 }
225 }
226 return NULL;
227 }
228
229 const char *
230 http_request_get_data(http_request_t *request, int *datalen)
231 {
232 assert(request);
233
234 if (datalen) {
235 *datalen = request->datalen;
236 }
237 return request->data;
238 }