source: mainline/uspace/lib/http/response.c@ 3ce68b7

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

libhttp: receive headers correctly

  • Property mode set to 100644
File size: 4.1 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.h"
42
43int http_parse_status(const char *line, http_version_t *out_version,
44 uint16_t *out_status, char **out_message)
45{
46 http_version_t version;
47 uint16_t status;
48 char *message = NULL;
49
50 if (!str_test_prefix(line, "HTTP/"))
51 return EINVAL;
52
53 const char *pos_version = line + 5;
54 const char *pos = pos_version;
55
56 int rc = str_uint8_t(pos_version, &pos, 10, false, &version.major);
57 if (rc != EOK)
58 return rc;
59 if (*pos != '.')
60 return EINVAL;
61 pos++;
62
63 pos_version = pos;
64 rc = str_uint8_t(pos_version, &pos, 10, false, &version.minor);
65 if (rc != EOK)
66 return rc;
67 if (*pos != ' ')
68 return EINVAL;
69 pos++;
70
71 const char *pos_status = pos;
72 rc = str_uint16_t(pos_status, &pos, 10, false, &status);
73 if (rc != EOK)
74 return rc;
75 if (*pos != ' ')
76 return EINVAL;
77 pos++;
78
79 if (out_message) {
80 message = str_dup(pos);
81 if (message == NULL)
82 return ENOMEM;
83 }
84
85 if (out_version)
86 *out_version = version;
87 if (out_status)
88 *out_status = status;
89 if (out_message)
90 *out_message = message;
91 return EOK;
92}
93
94int http_receive_response(http_t *http, http_response_t **out_response)
95{
96 http_response_t *resp = malloc(sizeof(http_response_t));
97 if (resp == NULL)
98 return ENOMEM;
99 memset(resp, 0, sizeof(http_response_t));
100 list_initialize(&resp->headers);
101
102 char *line = malloc(http->buffer_size);
103 if (line == NULL) {
104 free(resp);
105 return ENOMEM;
106 }
107
108 int rc = recv_line(&http->recv_buffer, line, http->buffer_size);
109 if (rc < 0)
110 goto error;
111
112 rc = http_parse_status(line, &resp->version, &resp->status,
113 &resp->message);
114 if (rc != EOK)
115 goto error;
116
117 while (true) {
118 rc = recv_eol(&http->recv_buffer);
119 if (rc < 0)
120 goto error;
121
122 /* Empty line ends header part */
123 if (rc > 0)
124 break;
125
126 http_header_t *header = malloc(sizeof(http_header_t));
127 if (header == NULL) {
128 rc = ENOMEM;
129 goto error;
130 }
131 http_header_init(header);
132
133 rc = http_header_receive(&http->recv_buffer, header);
134 if (rc != EOK) {
135 free(header);
136 goto error;
137 }
138
139 list_append(&header->link, &resp->headers);
140 }
141
142 *out_response = resp;
143
144 return EOK;
145error:
146 free(line);
147 http_response_destroy(resp);
148 return rc;
149}
150
151int http_receive_body(http_t *http, void *buf, size_t buf_size)
152{
153 return recv_buffer(&http->recv_buffer, buf, buf_size);
154}
155
156void http_response_destroy(http_response_t *resp)
157{
158 free(resp->message);
159 link_t *link = resp->headers.head.next;
160 while (link != &resp->headers.head) {
161 link_t *next = link->next;
162 http_header_t *header = list_get_instance(link, http_header_t, link);
163 http_header_destroy(header);
164 link = next;
165 }
166 free(resp);
167}
168
169/** @}
170 */
Note: See TracBrowser for help on using the repository browser.