vfs: check userland buffers before reading them.
[haiku.git] / src / add-ons / kernel / file_systems / googlefs / http_cnx.c
blobd27090215252f50d26e7360e48dbd475b1190915
1 /*
2 * Copyright 2004-2008, François Revol, <revol@free.fr>.
3 * Distributed under the terms of the MIT License.
4 */
6 #include <errno.h>
7 #include <sys/param.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <unistd.h>
12 #include "ksocket.h"
13 #include <netinet/in.h>
14 #include <arpa/inet.h>
15 #include "http_cnx.h"
17 //#define TESTME
19 #ifdef _KERNEL_MODE
20 #include <KernelExport.h>
21 #define printf dprintf
22 #undef TESTME
23 #endif
25 #define DBG "googlefs: http_cnx: "
27 #define HTTPVER "1.0"
29 //#define GOOGLEFS_UA "GoogleFS"
30 //Mozilla/3.0 (compatible; NetPositive/2.2.2; BeOS)
31 //Mozilla/5.0 (BeOS; U; BeOS BePC; en-US; rv:1.8.1.18) Gecko/20081114 BonEcho/2.0.0.18
32 #ifdef __HAIKU__
33 #define GOOGLEFS_UA "Mozilla/5.0 (compatible; GoogleFS/0.1; Haiku)"
34 #else
35 #define GOOGLEFS_UA "Mozilla/5.0 (compatible; GoogleFS/0.1; BeOS)"
36 #endif
38 #ifdef TESTME
39 #define BUFSZ (128*1024)
40 #endif
42 KSOCKET_MODULE_DECL;
44 status_t http_init()
46 return ksocket_init();
49 status_t http_uninit()
51 return ksocket_cleanup();
54 status_t http_create(struct http_cnx **cnx)
56 struct http_cnx *c;
57 int err;
58 c = malloc(sizeof(struct http_cnx));
59 if (!c)
60 return ENOMEM;
61 memset(c, 0, sizeof(struct http_cnx));
62 err = c->sock = ksocket(AF_INET, SOCK_STREAM, 0);
63 if (err < 0) {
64 free(c);
65 return errno;
67 *cnx = c;
68 return B_OK;
71 status_t http_delete(struct http_cnx *cnx)
73 if (!cnx)
74 return EINVAL;
75 if ((unsigned long)cnx < 0x40) {
76 dprintf("http: WARNING: cnx ptr = %p\n", cnx);
77 return B_OK;
79 if (cnx->sock >= 0) {
80 kclosesocket(cnx->sock);
81 cnx->sock = -1;
83 if (cnx->buffer)
84 free(cnx->buffer);
85 cnx->buffer = 0xaa55aa55;//XXX
86 free(cnx);
87 return B_OK;
90 status_t http_connect(struct http_cnx *cnx, struct sockaddr_in *sin)
92 int err;
93 uint32 ip;
94 uint16 port;
95 if (!sin) {
96 dprintf("http_connect(, NULL)!!\n");
97 return EINVAL;
99 ip = sin->sin_addr.s_addr;
100 port = sin->sin_port;
101 dprintf("http_connect(, %d.%d.%d.%d:%d), sock = %ld\n", ip & 0xff, (ip >> 8) & 0xff, (ip >> 16) & 0xff, (ip >> 24) & 0xff, ntohs(port), cnx->sock);
102 err = kconnect(cnx->sock, (struct sockaddr *)sin, sin->sin_len);
103 cnx->err = 0;
104 if (err == -1)
105 return errno;
106 return err;
109 status_t http_close(struct http_cnx *cnx)
111 int err;
112 if (!cnx)
113 return EINVAL;
114 if (cnx->sock < 0)
115 return 0;
116 err = kclosesocket(cnx->sock);
117 cnx->sock = -1;
118 return err;
121 status_t http_get(struct http_cnx *cnx, const char *url)
123 char *req, *p;
124 int reqlen;
125 int len;
126 int err;
127 long headerslen = 0;
128 long contentlen = 0;
129 if (strlen(url) > 4096 - 128)
130 return EINVAL;
131 req = malloc(4096+1);
132 if (!req)
133 return B_NO_MEMORY;
134 req[4096] = '\0';
135 /* no snprintf in kernel :( */
136 sprintf(req, "GET %s HTTP/"HTTPVER"\r\nUser-Agent: " GOOGLEFS_UA "\r\nAccept: */*\r\n\r\n", url);
137 reqlen = strlen(req);
138 err = len = write(cnx->sock, req, reqlen);
139 if (len < 1)
140 goto err0;
141 reqlen = 4096;
142 err = len = read(cnx->sock, req, reqlen);
143 printf("read(sock) = %d\n", len);
144 if (err < 0)
145 goto err0;
146 //write(1, req, len);
148 int fd;
149 // debug output
150 fd = open("/tmp/google.html_", O_CREAT|O_TRUNC|O_RDWR, 0644);
151 write(fd, req, len);
152 close(fd);
155 err = EINVAL;
156 if (len < 10)
157 goto err0;
158 if (!strstr(req, "HTTP/1.0 200"))
159 goto err0;
161 err = B_NO_MEMORY;
162 if (!strstr(req, "\r\n\r\n")) {
163 if (!strstr(req, "\n\n")) /* shouldn't happen */
164 goto err0;
165 headerslen = strstr(req, "\n\n") - req + 2;
166 req[headerslen-1] = '\0';
167 req[headerslen-2] = '\0';
168 } else {
169 headerslen = strstr(req, "\r\n\r\n") - req + 4;
170 req[headerslen-3] = '\0';
171 req[headerslen-4] = '\0';
173 if (headerslen < 2 || headerslen > 4095)
174 goto err0;
175 p = strstr(req, "HTTP/1.");
176 if (!p)
177 goto err0;
178 p += strlen("HTTP/1.");
179 if (strlen(p) < 5)
180 goto err0;
181 p += strlen("1 ");
182 cnx->err = strtol(p, &p, 10);
183 if (cnx->err < 200 || cnx->err > 299)
184 goto err0;
185 printf("REQ: %d\n", cnx->err);
186 contentlen = len - headerslen;
187 // if (!strstr(req, "\n\n") && !strstr(req, "\r\n\r\n"))
188 // goto err0;
189 while (len > 0) {
190 long left = reqlen - headerslen - contentlen;
191 if (left < 128) {
192 reqlen += 4096;
193 p = realloc(req, reqlen);
194 left += 4096;
195 if (!p)
196 goto err0;
197 req = p;
199 err = len = read(cnx->sock, req + headerslen + contentlen, left);
200 if (len < 0)
201 goto err0;
202 contentlen += len;
204 cnx->buffer = req;
205 cnx->headers = req;
206 cnx->headerslen = headerslen;
207 cnx->data = req + headerslen;
208 cnx->datalen = contentlen;
209 cnx->data[contentlen] = '\0'; /* we have at least 128 bytes allocated ahead */
210 return B_OK;
211 err0:
212 if (err > -1)
213 err = -1;
214 free(req);
215 return err;
230 #ifdef TESTME
231 //#define TESTURL "/"
232 //#define TESTURL "http://www.google.com/search?as_q=google+api+&num=50&hl=en&ie=ISO-8859-1&btnG=Google+Search&as_epq=frequently+asked&as_oq=help&as_eq=plop&lr=lang_en&as_ft=i&as_filetype=&as_qdr=m3&as_nlo=&as_nhi=&as_occt=any&as_dt=i&as_sitesearch="
233 #define TESTURL "http://www.google.com/search?hl=en&ie=UTF-8&num=50&q=beos"
234 int main(int argc, char **argv)
236 struct sockaddr_in sin;
237 struct http_cnx *cnx;
238 size_t len;
239 char *p;
240 int err;
242 http_init();
243 err = http_create(&cnx);
244 printf("error 0x%08lx\n", err);
245 sin.sin_len = sizeof(struct sockaddr_in);
246 sin.sin_family = AF_INET;
247 sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
248 inet_aton("66.102.11.99", &sin.sin_addr);
249 sin.sin_port = htons(80);
250 err = http_connect(cnx, &sin);
251 printf("error 0x%08lx\n", err);
252 err = http_get(cnx, TESTURL);
253 printf("error 0x%08lx\n", err);
254 if (err < 0)
255 return 1;
256 printf("HEADERS %d:%s\n", cnx->headerslen, cnx->headers);
257 printf("DATA: %d:%s\n", cnx->datalen, cnx->data);
258 http_close(cnx);
259 http_delete(cnx);
260 return 0;
262 #endif