Skip to content

Commit 3f1b638

Browse files
committed
HTTP protocol added
Signed-off-by: Martin Sustrik <[email protected]>
1 parent 8ddc91c commit 3f1b638

File tree

5 files changed

+416
-1
lines changed

5 files changed

+416
-1
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,3 +52,4 @@ tests/nacl
5252
tests/keepalive
5353
tests/fullstack
5454
tests/iovec
55+
tests/http

Makefile.am

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ libdsock_la_SOURCES = \
3939
crlf.c \
4040
fd.h \
4141
fd.c \
42+
http.c \
4243
iov.h \
4344
iov.c \
4445
ipaddr.c \
@@ -164,7 +165,8 @@ check_PROGRAMS = \
164165
tests/nacl \
165166
tests/keepalive \
166167
tests/fullstack \
167-
tests/iovec
168+
tests/iovec \
169+
tests/http
168170

169171
if HAVE_TLS
170172

dsock.h

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,53 @@ DSOCK_EXPORT int crlf_stop(
246246
int s,
247247
int64_t deadline);
248248

249+
/******************************************************************************/
250+
/* HTTP */
251+
/******************************************************************************/
252+
253+
DSOCK_EXPORT int http_start(
254+
int s);
255+
DSOCK_EXPORT int http_done(
256+
int s,
257+
int64_t deadline);
258+
DSOCK_EXPORT int http_stop(
259+
int s,
260+
int64_t deadline);
261+
DSOCK_EXPORT int http_sendrequest(
262+
int s,
263+
const char *command,
264+
const char *resource,
265+
int64_t deadline);
266+
DSOCK_EXPORT int http_recvrequest(
267+
int s,
268+
char *command,
269+
size_t commandlen,
270+
char *resource,
271+
size_t resourcelen,
272+
int64_t deadline);
273+
DSOCK_EXPORT int http_sendstatus(
274+
int s,
275+
int status,
276+
const char *reason,
277+
int64_t deadline);
278+
DSOCK_EXPORT int http_recvstatus(
279+
int s,
280+
char *reason,
281+
size_t reasonlen,
282+
int64_t deadline);
283+
DSOCK_EXPORT int http_sendfield(
284+
int s,
285+
const char *name,
286+
const char *value,
287+
int64_t deadline);
288+
DSOCK_EXPORT int http_recvfield(
289+
int s,
290+
char *name,
291+
size_t namelen,
292+
char *value,
293+
size_t valuelen,
294+
int64_t deadline);
295+
249296
/******************************************************************************/
250297
/* NaCl encryption and authentication protocol. */
251298
/* Uses crypto_secretbox_xsalsa20poly1305 algorithm. Key is 32B long. */

http.c

Lines changed: 271 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,271 @@
1+
/*
2+
3+
Copyright (c) 2016 Martin Sustrik
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"),
7+
to deal in the Software without restriction, including without limitation
8+
the rights to use, copy, modify, merge, publish, distribute, sublicense,
9+
and/or sell copies of the Software, and to permit persons to whom
10+
the Software is furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included
13+
in all copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18+
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21+
IN THE SOFTWARE.
22+
23+
*/
24+
25+
#include <errno.h>
26+
#include <stdint.h>
27+
#include <stdio.h>
28+
#include <stdlib.h>
29+
#include <string.h>
30+
31+
#include "iov.h"
32+
#include "bsock.h"
33+
#include "msock.h"
34+
#include "dsock.h"
35+
#include "utils.h"
36+
37+
dsock_unique_id(http_type);
38+
39+
static void *http_hquery(struct hvfs *hvfs, const void *type);
40+
static void http_hclose(struct hvfs *hvfs);
41+
42+
struct http_sock {
43+
struct hvfs hvfs;
44+
/* Underlying CRLF socket. */
45+
int s;
46+
int rxerr;
47+
char rxbuf[1024];
48+
};
49+
50+
static void *http_hquery(struct hvfs *hvfs, const void *type) {
51+
struct http_sock *obj = (struct http_sock*)hvfs;
52+
if(type == http_type) return obj;
53+
errno = ENOTSUP;
54+
return NULL;
55+
}
56+
57+
int http_start(int s) {
58+
int err;
59+
/* Check whether underlying socket is a bytestream. */
60+
if(dsock_slow(!hquery(s, bsock_type))) {err = errno; goto error1;}
61+
/* Create the object. */
62+
struct http_sock *obj = malloc(sizeof(struct http_sock));
63+
if(dsock_slow(!obj)) {err = ENOMEM; goto error1;}
64+
obj->hvfs.query = http_hquery;
65+
obj->hvfs.close = http_hclose;
66+
obj->s = -1;
67+
obj->rxerr = 0;
68+
/* Create the handle. */
69+
int h = hcreate(&obj->hvfs);
70+
if(dsock_slow(h < 0)) {err = errno; goto error2;}
71+
/* Wrap the underlying socket into CRLF protocol. */
72+
obj->s = crlf_start(s);
73+
if(dsock_slow(obj->s < 0)) {err = errno; goto error3;}
74+
return h;
75+
error3:;
76+
int rc = hclose(h);
77+
dsock_assert(rc == 0);
78+
error2:
79+
free(obj);
80+
error1:
81+
errno = err;
82+
return -1;
83+
84+
}
85+
86+
int http_done(int s, int64_t deadline) {
87+
struct http_sock *obj = hquery(s, http_type);
88+
if(dsock_slow(!obj)) return -1;
89+
return crlf_done(obj->s, deadline);
90+
}
91+
92+
int http_stop(int s, int64_t deadline) {
93+
struct http_sock *obj = hquery(s, http_type);
94+
if(dsock_slow(!obj)) return -1;
95+
int u = crlf_stop(obj->s, deadline);
96+
/* TODO: Handle errors. */
97+
free(obj);
98+
return u;
99+
}
100+
101+
int http_sendrequest(int s, const char *command, const char *resource,
102+
int64_t deadline) {
103+
struct http_sock *obj = hquery(s, http_type);
104+
if(dsock_slow(!obj)) return -1;
105+
/* TODO: command and resource should contain no spaces! */
106+
struct iovec iov[4];
107+
iov[0].iov_base = (void*)command;
108+
iov[0].iov_len = strlen(command);
109+
iov[1].iov_base = (void*)" ";
110+
iov[1].iov_len = 1;
111+
iov[2].iov_base = (void*)resource;
112+
iov[2].iov_len = strlen(resource);
113+
iov[3].iov_base = (void*)" HTTP/1.1";
114+
iov[3].iov_len = 9;
115+
return msendv(obj->s, iov, 4, deadline);
116+
}
117+
118+
int http_recvrequest(int s, char *command, size_t commandlen,
119+
char *resource, size_t resourcelen, int64_t deadline) {
120+
struct http_sock *obj = hquery(s, http_type);
121+
if(dsock_slow(!obj)) return -1;
122+
if(dsock_slow(obj->rxerr)) {errno = obj->rxerr; return -1;}
123+
ssize_t sz = mrecv(obj->s, obj->rxbuf, sizeof(obj->rxbuf) - 1, deadline);
124+
if(dsock_slow(sz < 0)) return -1;
125+
obj->rxbuf[sz] = 0;
126+
size_t pos = 0;
127+
while(obj->rxbuf[pos] == ' ') ++pos;
128+
/* Command. */
129+
size_t start = pos;
130+
while(obj->rxbuf[pos] != 0 && obj->rxbuf[pos] != ' ') ++pos;
131+
if(dsock_slow(obj->rxbuf[pos] == 0)) {errno = EPROTO; return -1;}
132+
if(dsock_slow(pos - start > commandlen - 1)) {errno = EMSGSIZE; return -1;}
133+
memcpy(command, obj->rxbuf + start, pos - start);
134+
command[pos - start] = 0;
135+
while(obj->rxbuf[pos] == ' ') ++pos;
136+
/* Resource. */
137+
start = pos;
138+
while(obj->rxbuf[pos] != 0 && obj->rxbuf[pos] != ' ') ++pos;
139+
if(dsock_slow(obj->rxbuf[pos] == 0)) {errno = EPROTO; return -1;}
140+
if(dsock_slow(pos - start > resourcelen - 1)) {errno = EMSGSIZE; return -1;}
141+
memcpy(resource, obj->rxbuf + start, pos - start);
142+
resource[pos - start] = 0;
143+
while(obj->rxbuf[pos] == ' ') ++pos;
144+
/* Protocol. */
145+
start = pos;
146+
while(obj->rxbuf[pos] != 0 && obj->rxbuf[pos] != ' ') ++pos;
147+
if(dsock_slow(pos - start != 8 &&
148+
memcmp(obj->rxbuf + start, "HTTP/1.1", 8) != 0)) {
149+
errno = EPROTO; return -1;}
150+
while(obj->rxbuf[pos] == ' ') ++pos;
151+
if(dsock_slow(obj->rxbuf[pos] != 0)) {errno = EPROTO; return -1;}
152+
return 0;
153+
}
154+
155+
int http_sendstatus(int s, int status, const char *reason, int64_t deadline) {
156+
struct http_sock *obj = hquery(s, http_type);
157+
if(dsock_slow(!obj)) return -1;
158+
if(dsock_slow(status < 100 || status > 599)) {errno = EINVAL; return -1;}
159+
char buf[4];
160+
buf[0] = (status / 100) + '0';
161+
status %= 100;
162+
buf[1] = (status / 10) + '0';
163+
status %= 10;
164+
buf[2] = status + '0';
165+
buf[3] = ' ';
166+
struct iovec iov[3];
167+
iov[0].iov_base = (void*)"HTTP/1.1 ";
168+
iov[0].iov_len = 9;
169+
iov[1].iov_base = buf;
170+
iov[1].iov_len = 4;
171+
iov[2].iov_base = (void*)reason;
172+
iov[2].iov_len = strlen(reason);
173+
return msendv(obj->s, iov, 3, deadline);
174+
}
175+
176+
int http_recvstatus(int s, char *reason, size_t reasonlen, int64_t deadline) {
177+
struct http_sock *obj = hquery(s, http_type);
178+
if(dsock_slow(!obj)) return -1;
179+
if(dsock_slow(obj->rxerr)) {errno = obj->rxerr; return -1;}
180+
ssize_t sz = mrecv(obj->s, obj->rxbuf, sizeof(obj->rxbuf) - 1, deadline);
181+
if(dsock_slow(sz < 0)) return -1;
182+
obj->rxbuf[sz] = 0;
183+
size_t pos = 0;
184+
while(obj->rxbuf[pos] == ' ') ++pos;
185+
/* Protocol. */
186+
size_t start = pos;
187+
while(obj->rxbuf[pos] != 0 && obj->rxbuf[pos] != ' ') ++pos;
188+
if(dsock_slow(obj->rxbuf[pos] == 0)) {errno = EPROTO; return -1;}
189+
if(dsock_slow(pos - start != 8 &&
190+
memcmp(obj->rxbuf + start, "HTTP/1.1", 8) != 0)) {
191+
errno = EPROTO; return -1;}
192+
while(obj->rxbuf[pos] == ' ') ++pos;
193+
/* Status code. */
194+
start = pos;
195+
while(obj->rxbuf[pos] != 0 && obj->rxbuf[pos] != ' ') ++pos;
196+
if(dsock_slow(obj->rxbuf[pos] == 0)) {errno = EPROTO; return -1;}
197+
if(dsock_slow(pos - start != 3)) {errno = EPROTO; return -1;}
198+
if(dsock_slow(obj->rxbuf[start] < '0' || obj->rxbuf[start] > '9' ||
199+
obj->rxbuf[start + 1] < '0' || obj->rxbuf[start + 1] > '9' ||
200+
obj->rxbuf[start + 2] < '0' || obj->rxbuf[start + 2] > '9')) {
201+
errno = EPROTO; return -1;}
202+
int status = (obj->rxbuf[start] - '0') * 100 +
203+
(obj->rxbuf[start + 1] - '0') * 10 +
204+
(obj->rxbuf[start + 2] - '0');
205+
while(obj->rxbuf[pos] == ' ') ++pos;
206+
/* Reason. */
207+
if(sz - pos > reasonlen - 1) {errno = EMSGSIZE; return -1;}
208+
memcpy(reason, obj->rxbuf + pos, sz - pos);
209+
reason[sz - pos] = 0;
210+
return status;
211+
}
212+
213+
int http_sendfield(int s, const char *name, const char *value,
214+
int64_t deadline) {
215+
struct http_sock *obj = hquery(s, http_type);
216+
if(dsock_slow(!obj)) return -1;
217+
/* TODO: Check whether name contains only valid characters! */
218+
struct iovec iov[3];
219+
iov[0].iov_base = (void*)name;
220+
iov[0].iov_len = strlen(name);
221+
iov[1].iov_base = (void*)": ";
222+
iov[1].iov_len = 2;
223+
iov[2].iov_base = (void*)value;
224+
iov[2].iov_len = strlen(value);
225+
return msendv(obj->s, iov, 3, deadline);
226+
}
227+
228+
int http_recvfield(int s, char *name, size_t namelen,
229+
char *value, size_t valuelen, int64_t deadline) {
230+
struct http_sock *obj = hquery(s, http_type);
231+
if(dsock_slow(!obj)) return -1;
232+
if(dsock_slow(obj->rxerr)) {errno = obj->rxerr; return -1;}
233+
ssize_t sz = mrecv(obj->s, obj->rxbuf, sizeof(obj->rxbuf) - 1, deadline);
234+
if(dsock_slow(sz < 0)) return -1;
235+
obj->rxbuf[sz] = 0;
236+
size_t pos = 0;
237+
while(obj->rxbuf[pos] == ' ') ++pos;
238+
/* Name. */
239+
size_t start = pos;
240+
while(obj->rxbuf[pos] != 0 &&
241+
obj->rxbuf[pos] != ' ' &&
242+
obj->rxbuf[pos] != ':')
243+
++pos;
244+
if(dsock_slow(obj->rxbuf[pos] == 0)) {errno = EPROTO; return -1;}
245+
if(dsock_slow(pos - start > namelen - 1)) {errno = EMSGSIZE; return -1;}
246+
memcpy(name, obj->rxbuf + start, pos - start);
247+
name[pos - start] = 0;
248+
while(obj->rxbuf[pos] == ' ') ++pos;
249+
if(dsock_slow(obj->rxbuf[pos] != ':')) {errno = EPROTO; return -1;}
250+
++pos;
251+
while(obj->rxbuf[pos] == ' ') ++pos;
252+
/* Value. */
253+
start = pos;
254+
while(obj->rxbuf[pos] != 0 && obj->rxbuf[pos] != ' ') ++pos;
255+
if(dsock_slow(pos - start > valuelen - 1)) {errno = EMSGSIZE; return -1;}
256+
memcpy(value, obj->rxbuf + start, pos - start);
257+
value[pos - start] = 0;
258+
while(obj->rxbuf[pos] == ' ') ++pos;
259+
if(dsock_slow(obj->rxbuf[pos] != 0)) {errno = EPROTO; return -1;}
260+
return 0;
261+
}
262+
263+
static void http_hclose(struct hvfs *hvfs) {
264+
struct http_sock *obj = (struct http_sock*)hvfs;
265+
if(dsock_fast(obj->s >= 0)) {
266+
int rc = hclose(obj->s);
267+
dsock_assert(rc == 0);
268+
}
269+
free(obj);
270+
}
271+

0 commit comments

Comments
 (0)