Fixed bug #844809.
1 | /* |
2 | * The contents of this file are subject to the AOLserver Public License |
3 | * Version 1.1 (the "License"); you may not use this file except in |
4 | * compliance with the License. You may obtain a copy of the License at |
5 | * http://aolserver.com/. |
6 | * |
7 | * Software distributed under the License is distributed on an "AS IS" |
8 | * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See |
9 | * the License for the specific language governing rights and limitations |
10 | * under the License. |
11 | * |
12 | * The Original Code is AOLserver Code and related documentation |
13 | * distributed by AOL. |
14 | * |
15 | * The Initial Developer of the Original Code is America Online, |
16 | * Inc. Portions created by AOL are Copyright (C) 1999 America Online, |
17 | * Inc. All Rights Reserved. |
18 | * |
19 | * Alternatively, the contents of this file may be used under the terms |
20 | * of the GNU General Public License (the "GPL"), in which case the |
21 | * provisions of GPL are applicable instead of those above. If you wish |
22 | * to allow use of your version of this file only under the terms of the |
23 | * GPL and not to allow others to use your version of this file under the |
24 | * License, indicate your decision by deleting the provisions above and |
25 | * replace them with the notice and other provisions required by the GPL. |
26 | * If you do not delete the provisions above, a recipient may use your |
27 | * version of this file under either the License or the GPL. |
28 | */ |
29 | |
30 | /* |
31 | * urlopen.c -- |
32 | * |
33 | * Make outgoing HTTP requests. |
34 | */ |
35 | |
36 | static const char *RCSID = "@(#) $Header: /cvsroot-fuse/aolserver/aolserver/nsd/urlopen.c,v 1.17 2003/12/28 00:22:06 scottg Exp $, compiled: " __DATE__ " " __TIME__; |
37 | |
38 | #include "nsd.h" |
39 | |
40 | #define BUFSIZE 2048 |
41 | |
42 | typedef struct Stream { |
43 | SOCKET sock; |
44 | int error; |
45 | int cnt; |
46 | char *ptr; |
47 | char buf[BUFSIZE+1]; |
48 | } Stream; |
49 | |
50 | /* |
51 | * Local functions defined in this file |
52 | */ |
53 | |
54 | static int <a href="/cvs/aolserver/aolserver/nscp/nscp.c#A_GetLine">GetLine</a>(Stream *sPtr, Ns_DString *dsPtr); |
55 | static int <a href="/cvs/aolserver/aolserver/nsd/urlopen.c#A_FillBuf">FillBuf</a>(Stream *sPtr); |
56 | |
57 | |
58 | /* |
59 | *---------------------------------------------------------------------- |
60 | * |
61 | * <a href="/cvs/aolserver/aolserver/nsd/urlopen.c#A_Ns_FetchPage">Ns_FetchPage</a> -- |
62 | * |
63 | * Fetch a page off of this very server. Url must reference a |
64 | * file in the filesystem. |
65 | * |
66 | * Results: |
67 | * NS_OK or NS_ERROR. |
68 | * |
69 | * Side effects: |
70 | * The file contents will be put into the passed-in dstring. |
71 | * |
72 | *---------------------------------------------------------------------- |
73 | */ |
74 | |
75 | int |
76 | <a href="/cvs/aolserver/aolserver/nsd/urlopen.c#A_Ns_FetchPage">Ns_FetchPage</a>(Ns_DString *dsPtr, char *url, char *server) |
77 | { |
78 | Ns_DString path; |
79 | int fd; |
80 | int nread; |
81 | char buf[1024]; |
82 | |
83 | <a href="/cvs/aolserver/aolserver/nsd/dstring.c#A_Ns_DStringInit">Ns_DStringInit</a>(&path); |
84 | <a href="/cvs/aolserver/aolserver/nsd/fastpath.c#A_Ns_UrlToFile">Ns_UrlToFile</a>(&path, server, url); |
85 | fd = open(path.string, O_RDONLY|O_BINARY); |
86 | <a href="/cvs/aolserver/aolserver/nsd/dstring.c#A_Ns_DStringFree">Ns_DStringFree</a>(&path); |
87 | if (fd < 0) { |
88 | return NS_ERROR; |
89 | } |
90 | while ((nread = read(fd, buf, sizeof(buf))) > 0) { |
91 | <a href="/cvs/aolserver/aolserver/nsd/dstring.c#A_Ns_DStringNAppend">Ns_DStringNAppend</a>(dsPtr, buf, nread); |
92 | } |
93 | close(fd); |
94 | return NS_OK; |
95 | } |
96 | |
97 | |
98 | /* |
99 | *---------------------------------------------------------------------- |
100 | * |
101 | * <a href="/cvs/aolserver/aolserver/nsd/urlopen.c#A_Ns_FetchURL">Ns_FetchURL</a> -- |
102 | * |
103 | * Open up an HTTP connection to an arbitrary URL. |
104 | * |
105 | * Results: |
106 | * NS_OK or NS_ERROR. |
107 | * |
108 | * Side effects: |
109 | * Page contents will be appended to the passed-in dstring. |
110 | * Headers returned to us will be put into the passed-in Ns_Set. |
111 | * The set name will be changed to a copy of the HTTP status line. |
112 | * |
113 | *---------------------------------------------------------------------- |
114 | */ |
115 | |
116 | int |
117 | <a href="/cvs/aolserver/aolserver/nsd/urlopen.c#A_Ns_FetchURL">Ns_FetchURL</a>(Ns_DString *dsPtr, char *url, Ns_Set *headers) |
118 | { |
119 | SOCKET sock; |
120 | char *p; |
121 | Ns_DString ds; |
122 | Stream stream; |
123 | Ns_Request *request; |
124 | int status, tosend, n; |
125 | |
126 | status = NS_ERROR; |
127 | sock = INVALID_SOCKET; |
128 | <a href="/cvs/aolserver/aolserver/nsd/dstring.c#A_Ns_DStringInit">Ns_DStringInit</a>(&ds); |
129 | |
130 | /* |
131 | * <a href="/cvs/aolserver/aolserver/nsd/adpparse.c#A_Parse">Parse</a> the URL and open a connection. |
132 | */ |
133 | |
134 | <a href="/cvs/aolserver/aolserver/nsd/dstring.c#A_Ns_DStringVarAppend">Ns_DStringVarAppend</a>(&ds, "GET ", url, " HTTP/1.0", NULL); |
135 | request = <a href="/cvs/aolserver/aolserver/nsd/request.c#A_Ns_ParseRequest">Ns_ParseRequest</a>(ds.string); |
136 | if (request == NULL || request->protocol == NULL || |
137 | !STREQ(request->protocol, "http") || request->host == NULL) { |
138 | <a href="/cvs/aolserver/aolserver/nsd/log.c#A_Ns_Log">Ns_Log</a>(Notice, "urlopen: invalid url '%s'", url); |
139 | goto done; |
140 | } |
141 | if (request->port == 0) { |
142 | request->port = 80; |
143 | } |
144 | sock = <a href="/cvs/aolserver/aolserver/nsd/sock.c#A_Ns_SockConnect">Ns_SockConnect</a>(request->host, request->port); |
145 | if (sock == INVALID_SOCKET) { |
146 | <a href="/cvs/aolserver/aolserver/nsd/log.c#A_Ns_Log">Ns_Log</a>(Error, "urlopen: failed to connect to '%s': '%s'", |
147 | url, ns_sockstrerror(ns_sockerrno)); |
148 | goto done; |
149 | } |
150 | |
151 | /* |
152 | * Send a simple HTTP GET request. |
153 | */ |
154 | |
155 | <a href="/cvs/aolserver/aolserver/nsd/dstring.c#A_Ns_DStringTrunc">Ns_DStringTrunc</a>(&ds, 0); |
156 | <a href="/cvs/aolserver/aolserver/nsd/dstring.c#A_Ns_DStringVarAppend">Ns_DStringVarAppend</a>(&ds, "GET ", request->url, NULL); |
157 | if (request->query != NULL) { |
158 | <a href="/cvs/aolserver/aolserver/nsd/dstring.c#A_Ns_DStringVarAppend">Ns_DStringVarAppend</a>(&ds, "?", request->query, NULL); |
159 | } |
160 | <a href="/cvs/aolserver/aolserver/nsd/dstring.c#A_Ns_DStringAppend">Ns_DStringAppend</a>(&ds, " HTTP/1.0\r\nAccept: */*\r\n\r\n"); |
161 | p = ds.string; |
162 | tosend = ds.length; |
163 | while (tosend > 0) { |
164 | n = send(sock, p, tosend, 0); |
165 | if (n == SOCKET_ERROR) { |
166 | <a href="/cvs/aolserver/aolserver/nsd/log.c#A_Ns_Log">Ns_Log</a>(Error, "urlopen: failed to send data to '%s': '%s'", |
167 | url, ns_sockstrerror(ns_sockerrno)); |
168 | goto done; |
169 | } |
170 | tosend -= n; |
171 | p += n; |
172 | } |
173 | |
174 | /* |
175 | * Buffer the socket and read the response line and then |
176 | * consume the headers, parsing them into any given header set. |
177 | */ |
178 | |
179 | stream.cnt = 0; |
180 | stream.error = 0; |
181 | stream.ptr = stream.buf; |
182 | stream.sock = sock; |
183 | if (!<a href="/cvs/aolserver/aolserver/nscp/nscp.c#A_GetLine">GetLine</a>(&stream, &ds)) { |
184 | goto done; |
185 | } |
186 | if (headers != NULL && strncmp(ds.string, "HTTP", 4) == 0) { |
187 | if (headers->name != NULL) { |
188 | ns_free(headers->name); |
189 | } |
190 | headers->name = <a href="/cvs/aolserver/aolserver/nsd/dstring.c#A_Ns_DStringExport">Ns_DStringExport</a>(&ds); |
191 | } |
192 | do { |
193 | if (!<a href="/cvs/aolserver/aolserver/nscp/nscp.c#A_GetLine">GetLine</a>(&stream, &ds)) { |
194 | goto done; |
195 | } |
196 | if (ds.length > 0 |
197 | && headers != NULL |
198 | && <a href="/cvs/aolserver/aolserver/nsd/request.c#A_Ns_ParseHeader">Ns_ParseHeader</a>(headers, ds.string, Preserve) != NS_OK) { |
199 | goto done; |
200 | } |
201 | } while (ds.length > 0); |
202 | |
203 | /* |
204 | * Without any check on limit or total size, foolishly read |
205 | * the remaining content into the dstring. |
206 | */ |
207 | |
208 | do { |
209 | <a href="/cvs/aolserver/aolserver/nsd/dstring.c#A_Ns_DStringNAppend">Ns_DStringNAppend</a>(dsPtr, stream.ptr, stream.cnt); |
210 | } while (<a href="/cvs/aolserver/aolserver/nsd/urlopen.c#A_FillBuf">FillBuf</a>(&stream)); |
211 | if (!stream.error) { |
212 | status = NS_OK; |
213 | } |
214 | |
215 | done: |
216 | if (request != NULL) { |
217 | <a href="/cvs/aolserver/aolserver/nsd/request.c#A_Ns_FreeRequest">Ns_FreeRequest</a>(request); |
218 | } |
219 | if (sock != INVALID_SOCKET) { |
220 | ns_sockclose(sock); |
221 | } |
222 | <a href="/cvs/aolserver/aolserver/nsd/dstring.c#A_Ns_DStringFree">Ns_DStringFree</a>(&ds); |
223 | return status; |
224 | } |
225 | |
226 | |
227 | /* |
228 | *---------------------------------------------------------------------- |
229 | * |
230 | * <a href="/cvs/aolserver/aolserver/nsd/urlopen.c#A_NsTclGetUrlObjCmd">NsTclGetUrlObjCmd</a> -- |
231 | * |
232 | * Implements ns_geturl. |
233 | * |
234 | * Results: |
235 | * Tcl result. |
236 | * |
237 | * Side effects: |
238 | * See docs. |
239 | * |
240 | *---------------------------------------------------------------------- |
241 | */ |
242 | |
243 | int |
244 | <a href="/cvs/aolserver/aolserver/nsd/urlopen.c#A_NsTclGetUrlObjCmd">NsTclGetUrlObjCmd</a>(ClientData arg, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) |
245 | { |
246 | NsInterp *itPtr = arg; |
247 | Ns_DString ds; |
248 | Ns_Set *headers; |
249 | int status, code; |
250 | char *url; |
251 | |
252 | if ((objc != 3) && (objc != 2)) { |
253 | Tcl_WrongNumArgs(interp, 1, objv, "url ?headersSetIdVar?"); |
254 | return TCL_ERROR; |
255 | } |
256 | |
257 | code = TCL_ERROR; |
258 | if (objc == 2) { |
259 | headers = NULL; |
260 | } else { |
261 | headers = <a href="/cvs/aolserver/aolserver/nsd/set.c#A_Ns_SetCreate">Ns_SetCreate</a>(NULL); |
262 | } |
263 | <a href="/cvs/aolserver/aolserver/nsd/dstring.c#A_Ns_DStringInit">Ns_DStringInit</a>(&ds); |
264 | url = Tcl_GetString(objv[1]); |
265 | if (url[0] == '/') { |
266 | status = <a href="/cvs/aolserver/aolserver/nsd/urlopen.c#A_Ns_FetchPage">Ns_FetchPage</a>(&ds, Tcl_GetString(objv[1]), itPtr->servPtr->server); |
267 | } else { |
268 | status = <a href="/cvs/aolserver/aolserver/nsd/urlopen.c#A_Ns_FetchURL">Ns_FetchURL</a>(&ds, Tcl_GetString(objv[1]), headers); |
269 | } |
270 | if (status != NS_OK) { |
271 | Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "could not fetch: ", |
272 | Tcl_GetString(objv[1]), NULL); |
273 | if (headers != NULL) { |
274 | <a href="/cvs/aolserver/aolserver/nsd/set.c#A_Ns_SetFree">Ns_SetFree</a>(headers); |
275 | } |
276 | goto done; |
277 | } |
278 | if (objc == 3) { |
279 | <a href="/cvs/aolserver/aolserver/nsd/tclset.c#A_Ns_TclEnterSet">Ns_TclEnterSet</a>(interp, headers, NS_TCL_SET_DYNAMIC); |
280 | if (Tcl_ObjSetVar2(interp, objv[2], NULL, Tcl_GetObjResult(interp), |
281 | TCL_LEAVE_ERR_MSG) == NULL) { |
282 | goto done; |
283 | } |
284 | } |
285 | Tcl_SetResult(interp, ds.string, TCL_VOLATILE); |
286 | code = TCL_OK; |
287 | |
288 | done: |
289 | <a href="/cvs/aolserver/aolserver/nsd/dstring.c#A_Ns_DStringFree">Ns_DStringFree</a>(&ds); |
290 | return code; |
291 | } |
292 | |
293 | |
294 | /* |
295 | *---------------------------------------------------------------------- |
296 | * |
297 | * <a href="/cvs/aolserver/aolserver/nsd/urlopen.c#A_FillBuf">FillBuf</a> -- |
298 | * |
299 | * Fill the socket stream buffer. |
300 | * |
301 | * Results: |
302 | * 1 if fill ok, 0 otherwise. |
303 | * |
304 | * Side effects: |
305 | * None. |
306 | * |
307 | *---------------------------------------------------------------------- |
308 | */ |
309 | |
310 | static int |
311 | <a href="/cvs/aolserver/aolserver/nsd/urlopen.c#A_FillBuf">FillBuf</a>(Stream *sPtr) |
312 | { |
313 | int n; |
314 | |
315 | n = recv(sPtr->sock, sPtr->buf, BUFSIZE, 0); |
316 | if (n <= 0) { |
317 | if (n < 0) { |
318 | <a href="/cvs/aolserver/aolserver/nsd/log.c#A_Ns_Log">Ns_Log</a>(Error, "urlopen: " |
319 | "failed to fill socket stream buffer: '%s'", strerror(errno)); |
320 | sPtr->error = 1; |
321 | } |
322 | return 0; |
323 | } |
324 | sPtr->buf[n] = '\0'; |
325 | sPtr->ptr = sPtr->buf; |
326 | sPtr->cnt = n; |
327 | return 1; |
328 | } |
329 | |
330 | |
331 | /* |
332 | *---------------------------------------------------------------------- |
333 | * |
334 | * <a href="/cvs/aolserver/aolserver/nscp/nscp.c#A_GetLine">GetLine</a> -- |
335 | * |
336 | * Copy the next line from the stream to a dstring, trimming |
337 | * the \n and \r. |
338 | * |
339 | * Results: |
340 | * 1 or 0. |
341 | * |
342 | * Side effects: |
343 | * The dstring is truncated on entry. |
344 | * |
345 | *---------------------------------------------------------------------- |
346 | */ |
347 | |
348 | static int |
349 | <a href="/cvs/aolserver/aolserver/nscp/nscp.c#A_GetLine">GetLine</a>(Stream *sPtr, Ns_DString *dsPtr) |
350 | { |
351 | char *eol; |
352 | int n; |
353 | |
354 | <a href="/cvs/aolserver/aolserver/nsd/dstring.c#A_Ns_DStringTrunc">Ns_DStringTrunc</a>(dsPtr, 0); |
355 | do { |
356 | if (sPtr->cnt > 0) { |
357 | eol = strchr(sPtr->ptr, '\n'); |
358 | if (eol == NULL) { |
359 | n = sPtr->cnt; |
360 | } else { |
361 | *eol++ = '\0'; |
362 | n = eol - sPtr->ptr; |
363 | } |
364 | <a href="/cvs/aolserver/aolserver/nsd/dstring.c#A_Ns_DStringNAppend">Ns_DStringNAppend</a>(dsPtr, sPtr->ptr, n - 1); |
365 | sPtr->ptr += n; |
366 | sPtr->cnt -= n; |
367 | if (eol != NULL) { |
368 | n = dsPtr->length; |
369 | if (n > 0 && dsPtr->string[n-1] == '\r') { |
370 | <a href="/cvs/aolserver/aolserver/nsd/dstring.c#A_Ns_DStringTrunc">Ns_DStringTrunc</a>(dsPtr, n-1); |
371 | } |
372 | return 1; |
373 | } |
374 | } |
375 | } while (<a href="/cvs/aolserver/aolserver/nsd/urlopen.c#A_FillBuf">FillBuf</a>(sPtr)); |
376 | return 0; |
377 | } |
Copyright © 2010 Geeknet, Inc. All rights reserved. Terms of Use