1 /*****************************************************************************
2  * chunked_test.c: HTTP 1.1 chunked encoding decoder test
3  *****************************************************************************
4  * Copyright (C) 2015 Rémi Denis-Courmont
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU Lesser General Public License as published by
8  * the Free Software Foundation; either version 2.1 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
19  *****************************************************************************/
20 
21 #ifdef HAVE_CONFIG_H
22 # include <config.h>
23 #endif
24 
25 #undef NDEBUG
26 
27 #include <assert.h>
28 #include <stddef.h>
29 #include <string.h>
30 
31 #include <vlc_common.h>
32 #include <vlc_tls.h>
33 #include <vlc_block.h>
34 #include "conn.h"
35 #include "message.h"
36 
37 /* I/O callbacks */
38 static const char *stream_content;
39 static size_t stream_length;
40 static bool stream_bad;
41 
fd_callback(struct vlc_tls * tls)42 static int fd_callback(struct vlc_tls *tls)
43 {
44     (void) tls;
45     return -1;
46 }
47 
recv_callback(struct vlc_tls * tls,struct iovec * iov,unsigned count)48 static ssize_t recv_callback(struct vlc_tls *tls, struct iovec *iov,
49                              unsigned count)
50 {
51     size_t rcvd = 0;
52 
53     while (count > 0)
54     {
55         size_t copy = iov->iov_len;
56         if (copy > stream_length)
57             copy = stream_length;
58 
59         if (copy > 0)
60         {
61             memcpy(iov->iov_base, stream_content, copy);
62             stream_content += copy;
63             stream_length -= copy;
64             rcvd += copy;
65         }
66 
67         iov++;
68         count--;
69     }
70     (void) tls;
71     return rcvd;
72 }
73 
close_callback(struct vlc_tls * tls)74 static void close_callback(struct vlc_tls *tls)
75 {
76     (void) tls;
77 }
78 
79 static struct vlc_tls chunked_tls =
80 {
81     .get_fd = fd_callback,
82     .readv = recv_callback,
83     .close = close_callback,
84 };
85 
stream_close_callback(struct vlc_http_stream * stream,bool bad)86 static void stream_close_callback(struct vlc_http_stream *stream, bool bad)
87 {
88     (void) stream;
89     assert(bad == stream_bad);
90 }
91 
92 static const struct vlc_http_stream_cbs chunked_stream_cbs =
93 {
94     .close = stream_close_callback,
95 };
96 
97 static struct vlc_http_stream chunked_stream =
98 {
99     &chunked_stream_cbs,
100 };
101 
102 /* Test cases */
103 
test_good(void)104 static void test_good(void)
105 {
106     struct vlc_http_stream *s;
107     block_t *b;
108 
109     /* Simple good payload */
110     stream_content =
111         "A\r\n" "1234567890\r\n"
112         "1A; ext-foo=1\r\n" "abcdefghijklmnopqrstuvwxyz\r\n"
113         "0\r\n" "\r\n";
114     stream_length = strlen(stream_content);
115     stream_bad = false;
116 
117     s = vlc_chunked_open(&chunked_stream, &chunked_tls);
118     assert(s != NULL);
119     assert(vlc_http_stream_read_headers(s) == NULL);
120 
121     b = vlc_http_stream_read(s);
122     assert(b != NULL);
123     assert(b->i_buffer == 10);
124     assert(!memcmp(b->p_buffer, "1234567890", 10));
125     block_Release(b);
126 
127     b = vlc_http_stream_read(s);
128     assert(b != NULL);
129     assert(b->i_buffer == 26);
130     assert(!memcmp(b->p_buffer, "abcdefghijklmnopqrstuvwxyz", 26));
131     block_Release(b);
132 
133     b = vlc_http_stream_read(s);
134     assert(b == NULL);
135     b = vlc_http_stream_read(s);
136     assert(b == NULL);
137 
138     vlc_http_stream_close(s, false);
139 }
140 
test_empty(void)141 static void test_empty(void)
142 {
143     struct vlc_http_stream *s;
144     block_t *b;
145 
146     stream_content = "0\r\n";
147     stream_length = 3;
148     stream_bad = true;
149 
150     s = vlc_chunked_open(&chunked_stream, &chunked_tls);
151     assert(s != NULL);
152 
153     b = vlc_http_stream_read(s);
154     assert(b == NULL);
155     b = vlc_http_stream_read(s);
156     assert(b == NULL);
157     vlc_http_stream_close(s, false);
158 }
159 
test_bad(const char * payload)160 static void test_bad(const char *payload)
161 {
162     struct vlc_http_stream *s;
163     block_t *b;
164 
165     stream_content = payload;
166     stream_length = strlen(payload);
167     stream_bad = true;
168 
169     s = vlc_chunked_open(&chunked_stream, &chunked_tls);
170     assert(s != NULL);
171 
172     while ((b = vlc_http_stream_read(s)) != vlc_http_error)
173     {
174         assert(b != NULL);
175         block_Release(b);
176     }
177 
178     vlc_http_stream_close(s, false);
179 }
180 
main(void)181 int main(void)
182 {
183     test_good();
184     test_empty();
185     test_bad("");
186     test_bad("A\r\n" "123456789");
187     test_bad("Z\r\n" "123456789");
188 
189     return 0;
190 }
191