There are no available options for this view.

Parent Directory Parent Directory | Revision <a href="/cvs/aolserver/aolserver/nsd/log.c#A_Log">Log</a> Revision <a href="/cvs/aolserver/aolserver/nsd/log.c#A_Log">Log</a>

Revision 1.17 - (show annotations) (download) (as text)
Sun Dec 28 00:22:06 2003 UTC (14 years ago) by scottg
Branch: MAIN
CVS Tags: aolserver_v45_r0, aolserver_v45_r2_rc0, HEAD
Branch point for: aolserver_v45_r1, aolserver_v45_r2, aolserver_v45_bp
Changes since 1.16: +3 -3 lines
File MIME type: text/x-chdr
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 }