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