source: mainline/uspace/lib/http/src/response.c@ 39b54fe

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 39b54fe was d5c1051, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 8 years ago

"Obviously harmless" error handling tweaks.

  • Property mode set to 100644
File size: 5.0 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 != EOK) {
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 size_t ndisc;
99 int rc = recv_discard_str(rb, expect, &ndisc);
100 if (rc != EOK)
101 return rc;
102 if (ndisc < str_length(expect))
103 return HTTP_EPARSE;
104 return EOK;
105}
106
107static bool is_not_newline(char c)
108{
109 return (c != '\n' && c != '\r');
110}
111
112int http_receive_status(receive_buffer_t *rb, http_version_t *out_version,
113 uint16_t *out_status, char **out_message)
114{
115 http_version_t version;
116 uint16_t status;
117 char *message = NULL;
118
119 int rc = expect(rb, "HTTP/");
120 if (rc != EOK)
121 return rc;
122
123 rc = receive_uint8_t(rb, &version.major);
124 if (rc != EOK)
125 return rc;
126
127 rc = expect(rb, ".");
128 if (rc != EOK)
129 return rc;
130
131 rc = receive_uint8_t(rb, &version.minor);
132 if (rc != EOK)
133 return rc;
134
135 rc = expect(rb, " ");
136 if (rc != EOK)
137 return rc;
138
139 rc = receive_uint16_t(rb, &status);
140 if (rc != EOK)
141 return rc;
142
143 rc = expect(rb, " ");
144 if (rc != EOK)
145 return rc;
146
147 receive_buffer_mark_t msg_start;
148 recv_mark(rb, &msg_start);
149
150 rc = recv_while(rb, is_not_newline);
151 if (rc != EOK) {
152 recv_unmark(rb, &msg_start);
153 return rc;
154 }
155
156 receive_buffer_mark_t msg_end;
157 recv_mark(rb, &msg_end);
158
159 if (out_message) {
160 rc = recv_cut_str(rb, &msg_start, &msg_end, &message);
161 if (rc != EOK) {
162 recv_unmark(rb, &msg_start);
163 recv_unmark(rb, &msg_end);
164 return rc;
165 }
166 }
167
168 recv_unmark(rb, &msg_start);
169 recv_unmark(rb, &msg_end);
170
171 size_t nrecv;
172 rc = recv_eol(rb, &nrecv);
173 if (rc == EOK && nrecv == 0)
174 rc = HTTP_EPARSE;
175 if (rc != EOK) {
176 free(message);
177 return rc;
178 }
179
180 if (out_version)
181 *out_version = version;
182 if (out_status)
183 *out_status = status;
184 if (out_message)
185 *out_message = message;
186 return EOK;
187}
188
189int http_receive_response(receive_buffer_t *rb, http_response_t **out_response,
190 size_t max_headers_size, unsigned max_headers_count)
191{
192 http_response_t *resp = malloc(sizeof(http_response_t));
193 if (resp == NULL)
194 return ENOMEM;
195 memset(resp, 0, sizeof(http_response_t));
196 http_headers_init(&resp->headers);
197
198 int rc = http_receive_status(rb, &resp->version, &resp->status,
199 &resp->message);
200 if (rc != EOK)
201 goto error;
202
203 rc = http_headers_receive(rb, &resp->headers, max_headers_size,
204 max_headers_count);
205 if (rc != EOK)
206 goto error;
207
208 size_t nrecv;
209 rc = recv_eol(rb, &nrecv);
210 if (rc == EOK && nrecv == 0)
211 rc = HTTP_EPARSE;
212 if (rc != EOK)
213 goto error;
214
215 *out_response = resp;
216
217 return EOK;
218error:
219 http_response_destroy(resp);
220 return rc;
221}
222
223void http_response_destroy(http_response_t *resp)
224{
225 free(resp->message);
226 http_headers_clear(&resp->headers);
227 free(resp);
228}
229
230/** @}
231 */
Note: See TracBrowser for help on using the repository browser.