source: mainline/uspace/lib/http/src/response.c@ 5918c00

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 5918c00 was cbfc8b7, checked in by Martin Sucha <sucha14@…>, 12 years ago

libhttp: Allow to specify limits when receiving HTTP response

  • Property mode set to 100644
File size: 4.9 KB
Line 
1/*
2 * Copyright (c) 2013 Martin Sucha
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup http
30 * @{
31 */
32/**
33 * @file
34 */
35
36#include <stdio.h>
37#include <stdlib.h>
38#include <str.h>
39#include <macros.h>
40
41#include <http/http.h>
42#include <http/errno.h>
43
44static bool is_digit(char c)
45{
46 return (c >= '0' && c <= '9');
47}
48
49static int receive_number(receive_buffer_t *rb, char **str)
50{
51 receive_buffer_mark_t start;
52 receive_buffer_mark_t end;
53
54 recv_mark(rb, &start);
55 int rc = recv_while(rb, is_digit);
56 if (rc < 0) {
57 recv_unmark(rb, &start);
58 return rc;
59 }
60 recv_mark(rb, &end);
61
62 rc = recv_cut_str(rb, &start, &end, str);
63 recv_unmark(rb, &start);
64 recv_unmark(rb, &end);
65 return rc;
66}
67
68static int receive_uint8_t(receive_buffer_t *rb, uint8_t *out_value)
69{
70 char *str = NULL;
71 int rc = receive_number(rb, &str);
72
73 if (rc != EOK)
74 return rc;
75
76 rc = str_uint8_t(str, NULL, 10, true, out_value);
77 free(str);
78
79 return rc;
80}
81
82static int receive_uint16_t(receive_buffer_t *rb, uint16_t *out_value)
83{
84 char *str = NULL;
85 int rc = receive_number(rb, &str);
86
87 if (rc != EOK)
88 return rc;
89
90 rc = str_uint16_t(str, NULL, 10, true, out_value);
91 free(str);
92
93 return rc;
94}
95
96static int expect(receive_buffer_t *rb, const char *expect)
97{
98 int rc = recv_discard_str(rb, expect);
99 if (rc < 0)
100 return rc;
101 if ((size_t) rc < str_length(expect))
102 return HTTP_EPARSE;
103 return EOK;
104}
105
106static bool is_not_newline(char c)
107{
108 return (c != '\n' && c != '\r');
109}
110
111int http_receive_status(receive_buffer_t *rb, http_version_t *out_version,
112 uint16_t *out_status, char **out_message)
113{
114 http_version_t version;
115 uint16_t status;
116 char *message = NULL;
117
118 int rc = expect(rb, "HTTP/");
119 if (rc != EOK)
120 return rc;
121
122 rc = receive_uint8_t(rb, &version.major);
123 if (rc != EOK)
124 return rc;
125
126 rc = expect(rb, ".");
127 if (rc != EOK)
128 return rc;
129
130 rc = receive_uint8_t(rb, &version.minor);
131 if (rc != EOK)
132 return rc;
133
134 rc = expect(rb, " ");
135 if (rc != EOK)
136 return rc;
137
138 rc = receive_uint16_t(rb, &status);
139 if (rc != EOK)
140 return rc;
141
142 rc = expect(rb, " ");
143 if (rc != EOK)
144 return rc;
145
146 receive_buffer_mark_t msg_start;
147 recv_mark(rb, &msg_start);
148
149 rc = recv_while(rb, is_not_newline);
150 if (rc < 0) {
151 recv_unmark(rb, &msg_start);
152 return rc;
153 }
154
155 receive_buffer_mark_t msg_end;
156 recv_mark(rb, &msg_end);
157
158 if (out_message) {
159 rc = recv_cut_str(rb, &msg_start, &msg_end, &message);
160 if (rc != EOK) {
161 recv_unmark(rb, &msg_start);
162 recv_unmark(rb, &msg_end);
163 return rc;
164 }
165 }
166
167 recv_unmark(rb, &msg_start);
168 recv_unmark(rb, &msg_end);
169
170 rc = recv_eol(rb);
171 if (rc == 0)
172 rc = HTTP_EPARSE;
173 if (rc < 0) {
174 free(message);
175 return rc;
176 }
177
178 if (out_version)
179 *out_version = version;
180 if (out_status)
181 *out_status = status;
182 if (out_message)
183 *out_message = message;
184 return EOK;
185}
186
187int http_receive_response(receive_buffer_t *rb, http_response_t **out_response,
188 size_t max_headers_size, unsigned max_headers_count)
189{
190 http_response_t *resp = malloc(sizeof(http_response_t));
191 if (resp == NULL)
192 return ENOMEM;
193 memset(resp, 0, sizeof(http_response_t));
194 http_headers_init(&resp->headers);
195
196 int rc = http_receive_status(rb, &resp->version, &resp->status,
197 &resp->message);
198 if (rc != EOK)
199 goto error;
200
201 rc = http_headers_receive(rb, &resp->headers, max_headers_size,
202 max_headers_count);
203 if (rc != EOK)
204 goto error;
205
206 rc = recv_eol(rb);
207 if (rc == 0)
208 rc = HTTP_EPARSE;
209 if (rc < 0)
210 goto error;
211
212 *out_response = resp;
213
214 return EOK;
215error:
216 http_response_destroy(resp);
217 return rc;
218}
219
220void http_response_destroy(http_response_t *resp)
221{
222 free(resp->message);
223 http_headers_clear(&resp->headers);
224 free(resp);
225}
226
227/** @}
228 */
Note: See TracBrowser for help on using the repository browser.