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