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.24 - (show annotations) (download) (as text)
Mon Mar 12 20:29:44 2007 UTC (10 years, 9 months ago) by shmooved
Branch: MAIN
CVS Tags: aolserver_v45_r2_rc0, HEAD
Branch point for: aolserver_v45_r1, aolserver_v45_r2
Changes since 1.23: +29 -24 lines
File MIME type: text/x-chdr
Preliminary support added for getting and retrieving binary data.
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 * tclhttp.c --
32 *
33 * Support for the ns_http command.
34 */
35
36 static const char *RCSID = "@(#) $Header: /cvsroot-fuse/aolserver/aolserver/nsd/tclhttp.c,v 1.24 2007/03/12 20:29:44 shmooved Exp $, compiled: " __DATE__ " " __TIME__;
37
38 #include "nsd.h"
39
40 extern Tcl_ObjCmdProc <a href="/cvs/aolserver/aolserver/nsd/tclhttp.c#A_NsTclHttpObjCmd">NsTclHttpObjCmd</a>;
41
42 typedef struct {
43 Ns_Task *task;
44 SOCKET sock;
45 char *error;
46 char *next;
47 size_t len;
48 int status;
49 Ns_Time timeout;
50 Ns_Time stime;
51 Ns_Time etime;
52 Tcl_DString ds;
53 } Http;
54
55 /*
56 * Local functions defined in this file
57 */
58
59 static int <a href="/cvs/aolserver/aolserver/nsd/tclhttp.c#A_HttpWaitCmd">HttpWaitCmd</a>(NsInterp *itPtr, int objc, Tcl_Obj **objv);
60 static int <a href="/cvs/aolserver/aolserver/nsd/tclhttp.c#A_HttpQueueCmd">HttpQueueCmd</a>(NsInterp *itPtr, int objc, Tcl_Obj **objv, int run);
61 static int <a href="/cvs/aolserver/aolserver/nsd/tclhttp.c#A_SetWaitVar">SetWaitVar</a>(Tcl_Interp *interp, Tcl_Obj *varPtr, Tcl_Obj *valPtr);
62 static int <a href="/cvs/aolserver/aolserver/nsd/tclhttp.c#A_HttpConnect">HttpConnect</a>(Tcl_Interp *interp, char *method, char *url,
63 Ns_Set *hdrs, Tcl_Obj *bodyPtr, Http **httpPtrPtr);
64 static char *<a href="/cvs/aolserver/aolserver/nsd/tclhttp.c#A_HttpResult">HttpResult</a>(Tcl_DString ds, int *statusPtr, Ns_Set *hdrs, Tcl_Obj **objPtrPtr);
65 static void <a href="/cvs/aolserver/aolserver/nsd/tclhttp.c#A_HttpClose">HttpClose</a>(Http *httpPtr);
66 static void <a href="/cvs/aolserver/aolserver/nsd/tclhttp.c#A_HttpCancel">HttpCancel</a>(Http *httpPtr);
67 static void <a href="/cvs/aolserver/aolserver/nsd/tclhttp.c#A_HttpAbort">HttpAbort</a>(Http *httpPtr);
68 static int <a href="/cvs/aolserver/aolserver/nsd/tclhttp.c#A_GetHttp">GetHttp</a>(NsInterp *itPtr, Tcl_Obj *obj, Http **httpPtrPtr);
69 static Ns_TaskProc <a href="/cvs/aolserver/aolserver/nsd/tclhttp.c#A_HttpProc">HttpProc</a>;
70
71 /*
72 * Static variables defined in this file.
73 */
74
75 static Ns_TaskQueue *queue;
76
77
78 /*
79 *----------------------------------------------------------------------
80 *
81 * <a href="/cvs/aolserver/aolserver/nsd/tclhttp.c#A_NsTclNHttpObjCmd">NsTclNHttpObjCmd</a> --
82 *
83 * Implements the new ns_http to handle HTTP requests.
84 *
85 * Results:
86 * Standard Tcl result.
87 *
88 * Side effects:
89 * May queue an HTTP request.
90 *
91 *----------------------------------------------------------------------
92 */
93
94 int
95 <a href="/cvs/aolserver/aolserver/nsd/tclhttp.c#A_NsTclNHttpObjCmd">NsTclNHttpObjCmd</a>(ClientData arg, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[])
96 {
97 NsInterp *itPtr = arg;
98 Http *httpPtr;
99 Tcl_HashEntry *hPtr;
100 Tcl_HashSearch search;
101 int run = 0;
102 static CONST char *opts[] = {
103 "cancel", "cleanup", "run", "queue", "wait", NULL
104 };
105 enum {
106 HCancelIdx, HCleanupIdx, HRunIdx, HQueueIdx, HWaitIdx
107 } opt;
108
109 if (objc < 2) {
110 Tcl_WrongNumArgs(interp, 1, objv, "option ?args ...?");
111 return TCL_ERROR;
112 }
113 if (Tcl_GetIndexFromObj(interp, objv[1], opts, "option", 0,
114 (int *) &opt) != TCL_OK) {
115 return TCL_ERROR;
116 }
117
118 switch (opt) {
119 case HRunIdx:
120 run = 1;
121 /* FALLTHROUGH */
122 case HQueueIdx:
123 return <a href="/cvs/aolserver/aolserver/nsd/tclhttp.c#A_HttpQueueCmd">HttpQueueCmd</a>(itPtr, objc, objv, run);
124 break;
125
126 case HWaitIdx:
127 return <a href="/cvs/aolserver/aolserver/nsd/tclhttp.c#A_HttpWaitCmd">HttpWaitCmd</a>(itPtr, objc, objv);
128 break;
129
130 case HCancelIdx:
131 if (objc != 2) {
132 Tcl_WrongNumArgs(interp, 2, objv, "id");
133 return TCL_ERROR;
134 }
135 if (!<a href="/cvs/aolserver/aolserver/nsd/tclhttp.c#A_GetHttp">GetHttp</a>(itPtr, objv[2], &httpPtr)) {
136 return TCL_ERROR;
137 }
138 <a href="/cvs/aolserver/aolserver/nsd/tclhttp.c#A_HttpAbort">HttpAbort</a>(httpPtr);
139 break;
140
141 case HCleanupIdx:
142 hPtr = Tcl_FirstHashEntry(&itPtr->https, &search);
143 while (hPtr != NULL) {
144 httpPtr = Tcl_GetHashValue(hPtr);
145 <a href="/cvs/aolserver/aolserver/nsd/tclhttp.c#A_HttpAbort">HttpAbort</a>(httpPtr);
146 hPtr = Tcl_NextHashEntry(&search);
147 }
148 Tcl_DeleteHashTable(&itPtr->https);
149 Tcl_InitHashTable(&itPtr->https, TCL_STRING_KEYS);
150 break;
151 }
152 return TCL_OK;
153 }
154
155
156 /*
157 *----------------------------------------------------------------------
158 *
159 * <a href="/cvs/aolserver/aolserver/nsd/tclhttp.c#A_HttpQueueCmd">HttpQueueCmd</a> --
160 *
161 * Implements "ns_http queue" subcommand.
162 *
163 * Results:
164 * Standard Tcl result.
165 *
166 * Side effects:
167 * May queue an HTTP request.
168 *
169 *----------------------------------------------------------------------
170 */
171
172 static int
173 <a href="/cvs/aolserver/aolserver/nsd/tclhttp.c#A_HttpQueueCmd">HttpQueueCmd</a>(NsInterp *itPtr, int objc, Tcl_Obj **objv, int run)
174 {
175 Tcl_Interp *interp = itPtr->interp;
176 int new, i;
177 Tcl_HashEntry *hPtr;
178 Http *httpPtr;
179 char buf[100], *arg, *url;
180 char *method = "GET";
181 Ns_Set *hdrs = NULL;
182 Tcl_Obj *bodyPtr = NULL;
183 Ns_Time incr;
184 static CONST char *opts[] = {
185 "-method", "-timeout", "-body", "-headers", NULL
186 };
187 enum {
188 QMethodIdx, QTimeoutIdx, QBodyIdx, QHeadersIdx
189 } opt;
190
191 incr.sec = 2;
192 incr.usec = 0;
193 for (i = 2; i < objc; ++i) {
194 arg = Tcl_GetString(objv[i]);
195 if (arg[0] != '-') {
196 break;
197 }
198 if (Tcl_GetIndexFromObj(interp, objv[i], opts, "option", 0,
199 (int *) &opt) != TCL_OK) {
200 return TCL_ERROR;
201 }
202 if ((i + 2) == objc) {
203 Tcl_AppendResult(interp, "no argument given to ", opts[opt], NULL);
204 return TCL_ERROR;
205 }
206 ++i;
207 switch (opt) {
208 case QMethodIdx:
209 method = Tcl_GetString(objv[i]);
210 break;
211 case QTimeoutIdx:
212 if (<a href="/cvs/aolserver/aolserver/nsd/tclobj.c#A_Ns_TclGetTimeFromObj">Ns_TclGetTimeFromObj</a>(interp, objv[i], &incr) != TCL_OK) {
213 return TCL_ERROR;
214 }
215 break;
216 case QBodyIdx:
217 bodyPtr = objv[i];
218 break;
219 case QHeadersIdx:
220 if (<a href="/cvs/aolserver/aolserver/nsd/tclset.c#A_Ns_TclGetSet2">Ns_TclGetSet2</a>(interp, Tcl_GetString(objv[i]),
221 &hdrs) != TCL_OK) {
222 return TCL_ERROR;
223 }
224 break;
225 }
226 }
227 if ((objc - i) != 1) {
228 Tcl_WrongNumArgs(interp, 2, objv, "?flags? url");
229 return TCL_ERROR;
230 }
231 url = Tcl_GetString(objv[i]);
232 if (!<a href="/cvs/aolserver/aolserver/nsd/tclhttp.c#A_HttpConnect">HttpConnect</a>(interp, method, url, hdrs, bodyPtr, &httpPtr)) {
233 return TCL_ERROR;
234 }
235 Ns_GetTime(&httpPtr->stime);
236 httpPtr->timeout = httpPtr->stime;
237 Ns_IncrTime(&httpPtr->timeout, incr.sec, incr.usec);
238 httpPtr->task = <a href="/cvs/aolserver/aolserver/nsd/task.c#A_Ns_TaskCreate">Ns_TaskCreate</a>(httpPtr->sock, <a href="/cvs/aolserver/aolserver/nsd/tclhttp.c#A_HttpProc">HttpProc</a>, httpPtr);
239 if (run) {
240 <a href="/cvs/aolserver/aolserver/nsd/task.c#A_Ns_TaskRun">Ns_TaskRun</a>(httpPtr->task);
241 } else {
242 if (queue == NULL) {
243 Ns_MasterLock();
244 if (queue == NULL) {
245 queue = <a href="/cvs/aolserver/aolserver/nsd/task.c#A_Ns_CreateTaskQueue">Ns_CreateTaskQueue</a>("tclhttp");
246 }
247 Ns_MasterUnlock();
248 }
249 if (<a href="/cvs/aolserver/aolserver/nsd/task.c#A_Ns_TaskEnqueue">Ns_TaskEnqueue</a>(httpPtr->task, queue) != NS_OK) {
250 <a href="/cvs/aolserver/aolserver/nsd/tclhttp.c#A_HttpClose">HttpClose</a>(httpPtr);
251 Tcl_AppendResult(interp, "could not queue http task", NULL);
252 return TCL_ERROR;
253 }
254 }
255 i = itPtr->https.numEntries;
256 do {
257 sprintf(buf, "http%d", i++);
258 hPtr = Tcl_CreateHashEntry(&itPtr->https, buf, &new);
259 } while (!new);
260 Tcl_SetHashValue(hPtr, httpPtr);
261 Tcl_SetResult(interp, buf, TCL_VOLATILE);
262 return TCL_OK;
263 }
264
265
266 /*
267 *----------------------------------------------------------------------
268 *
269 * <a href="/cvs/aolserver/aolserver/nsd/tclhttp.c#A_HttpWaitCmd">HttpWaitCmd</a> --
270 *
271 * Implements "ns_http wait" subcommand.
272 *
273 * Results:
274 * Standard Tcl result.
275 *
276 * Side effects:
277 * May queue an HTTP request.
278 *
279 *----------------------------------------------------------------------
280 */
281
282 static int
283 <a href="/cvs/aolserver/aolserver/nsd/tclhttp.c#A_HttpWaitCmd">HttpWaitCmd</a>(NsInterp *itPtr, int objc, Tcl_Obj **objv)
284 {
285 Tcl_Interp *interp = itPtr->interp;
286 Tcl_Obj *valPtr;
287 Tcl_Obj *elapsedPtr = NULL;
288 Tcl_Obj *resultPtr = NULL;
289 Tcl_Obj *statusPtr = NULL;
290 Tcl_Obj *responsePtr;
291 Ns_Set *hdrs = NULL;
292 Ns_Time diff;
293 char *arg, *content;
294 Http *httpPtr;
295 int result = TCL_ERROR;
296 int i, status;
297 static CONST char *opts[] = {
298 "-elapsed", "-result", "-headers", "-status", NULL
299 };
300 enum {
301 WElapsedIdx, WResultIdx, WHeadersIdx, WStatusIdx
302 } opt;
303
304 for (i = 2; i < objc; ++i) {
305 arg = Tcl_GetString(objv[i]);
306 if (arg[0] != '-') {
307 break;
308 }
309 if (Tcl_GetIndexFromObj(interp, objv[i], opts, "option", 0,
310 (int *) &opt) != TCL_OK) {
311 return TCL_ERROR;
312 }
313 if (++i == objc) {
314 Tcl_AppendResult(interp, "no argument given to ", opts[opt], NULL);
315 return TCL_ERROR;
316 }
317 switch (opt) {
318 case WElapsedIdx:
319 elapsedPtr = objv[i];
320 break;
321 case WResultIdx:
322 resultPtr = objv[i];
323 break;
324 case WStatusIdx:
325 statusPtr = objv[i];
326 break;
327 case WHeadersIdx:
328 if (<a href="/cvs/aolserver/aolserver/nsd/tclset.c#A_Ns_TclGetSet2">Ns_TclGetSet2</a>(interp, Tcl_GetString(objv[i]),
329 &hdrs) != TCL_OK) {
330 return TCL_ERROR;
331 }
332 break;
333 }
334 }
335 if ((objc - i) != 1) {
336 Tcl_WrongNumArgs(interp, 2, objv, "?flags? id");
337 return TCL_ERROR;
338 }
339 if (!<a href="/cvs/aolserver/aolserver/nsd/tclhttp.c#A_GetHttp">GetHttp</a>(itPtr, objv[i], &httpPtr)) {
340 return TCL_ERROR;
341 }
342 if (<a href="/cvs/aolserver/aolserver/nsd/task.c#A_Ns_TaskWait">Ns_TaskWait</a>(httpPtr->task, NULL) != NS_OK) {
343 <a href="/cvs/aolserver/aolserver/nsd/tclhttp.c#A_HttpCancel">HttpCancel</a>(httpPtr);
344 Tcl_AppendResult(interp, "timeout waiting for task", NULL);
345 return TCL_ERROR;
346 }
347 result = TCL_ERROR;
348 if (elapsedPtr != NULL) {
349 Ns_DiffTime(&httpPtr->etime, &httpPtr->stime, &diff);
350 valPtr = Tcl_NewObj();
351 <a href="/cvs/aolserver/aolserver/nsd/tclobj.c#A_Ns_TclSetTimeObj">Ns_TclSetTimeObj</a>(valPtr, &diff);
352 if (!<a href="/cvs/aolserver/aolserver/nsd/tclhttp.c#A_SetWaitVar">SetWaitVar</a>(interp, elapsedPtr, valPtr)) {
353 goto err;
354 }
355 }
356 if (httpPtr->error) {
357 Tcl_AppendResult(interp, "http failed: ", httpPtr->error, NULL);
358 goto err;
359 }
360 content = <a href="/cvs/aolserver/aolserver/nsd/tclhttp.c#A_HttpResult">HttpResult</a>(httpPtr->ds, &status, hdrs, &responsePtr);
361 if (statusPtr != NULL &&
362 !<a href="/cvs/aolserver/aolserver/nsd/tclhttp.c#A_SetWaitVar">SetWaitVar</a>(interp, statusPtr, Tcl_NewIntObj(status))) {
363 goto err;
364 }
365 if (resultPtr == NULL) {
366 Tcl_SetObjResult(interp, responsePtr);
367 } else {
368 if (!<a href="/cvs/aolserver/aolserver/nsd/tclhttp.c#A_SetWaitVar">SetWaitVar</a>(interp, resultPtr, responsePtr)) {
369 goto err;
370 }
371 Tcl_SetBooleanObj(Tcl_GetObjResult(interp), 1);
372 }
373 result = TCL_OK;
374
375 err:
376 <a href="/cvs/aolserver/aolserver/nsd/tclhttp.c#A_HttpClose">HttpClose</a>(httpPtr);
377 return result;
378 }
379
380
381 /*
382 *----------------------------------------------------------------------
383 *
384 * <a href="/cvs/aolserver/aolserver/nsd/tclhttp.c#A_GetHttp">GetHttp</a> --
385 *
386 * Locate and remove the Http struct for a given id.
387 *
388 * Results:
389 * 1 on success, 0 otherwise.
390 *
391 * Side effects:
392 * Will update given httpPtrPtr with pointer to Http struct.
393 *
394 *----------------------------------------------------------------------
395 */
396
397 static int
398 <a href="/cvs/aolserver/aolserver/nsd/tclhttp.c#A_GetHttp">GetHttp</a>(NsInterp *itPtr, Tcl_Obj *obj, Http **httpPtrPtr)
399 {
400 Tcl_HashEntry *hPtr;
401 char *id;
402
403 id = Tcl_GetString(obj);
404 hPtr = Tcl_FindHashEntry(&itPtr->https, id);
405 if (hPtr == NULL) {
406 Tcl_AppendResult(itPtr->interp, "no such request: ", id, NULL);
407 return 0;
408 }
409 *httpPtrPtr = Tcl_GetHashValue(hPtr);
410 Tcl_DeleteHashEntry(hPtr);
411 return 1;
412 }
413
414
415 /*
416 *----------------------------------------------------------------------
417 *
418 * <a href="/cvs/aolserver/aolserver/nsd/tclhttp.c#A_SetWaitVar">SetWaitVar</a> --
419 *
420 * Set a variable by name. Convience routine for for <a href="/cvs/aolserver/aolserver/nsd/tclhttp.c#A_HttpWaitCmd">HttpWaitCmd</a>.
421 *
422 * Results:
423 * 1 on success, 0 otherwise.
424 *
425 * Side effects:
426 * None.
427 *
428 *----------------------------------------------------------------------
429 */
430
431 static int
432 <a href="/cvs/aolserver/aolserver/nsd/tclhttp.c#A_SetWaitVar">SetWaitVar</a>(Tcl_Interp *interp, Tcl_Obj *varPtr, Tcl_Obj *valPtr)
433 {
434 Tcl_Obj *errPtr;
435
436 Tcl_IncrRefCount(valPtr);
437 errPtr = Tcl_ObjSetVar2(interp, varPtr, NULL, valPtr,
438 TCL_PARSE_PART1|TCL_LEAVE_ERR_MSG);
439 Tcl_DecrRefCount(valPtr);
440 return (errPtr ? 1 : 0);
441 }
442
443
444 /*
445 *----------------------------------------------------------------------
446 *
447 * <a href="/cvs/aolserver/aolserver/nsd/tclhttp.c#A_HttpConnect">HttpConnect</a> --
448 *
449 * Open a connection to the given URL host and construct
450 * an Http structure to fetch the file.
451 *
452 * Results:
453 * 1 if successful, 0 otherwise.
454 *
455 * Side effects:
456 * Updates httpPtrPtr with newly allocated Http struct.
457 *
458 *----------------------------------------------------------------------
459 */
460
461 int
462 <a href="/cvs/aolserver/aolserver/nsd/tclhttp.c#A_HttpConnect">HttpConnect</a>(Tcl_Interp *interp, char *method, char *url, Ns_Set *hdrs,
463 Tcl_Obj *bodyPtr, Http **httpPtrPtr)
464 {
465 Http *httpPtr = NULL;
466 SOCKET sock;
467 char *body, *host, *file, *port;
468 int i, len;
469
470 if (strncmp(url, "http://", 7) != 0 || url[7] == '\0') {
471 Tcl_AppendResult(interp, "invalid url: ", url, NULL);
472 return 0;
473 }
474 host = url + 7;
475 file = strchr(host, '/');
476 if (file != NULL) {
477 *file = '\0';
478 }
479 port = strchr(host, ':');
480 if (port == NULL) {
481 i = 80;
482 } else {
483 *port = '\0';
484 i = (int) strtol(port+1, NULL, 10);
485 }
486 sock = <a href="/cvs/aolserver/aolserver/nsd/sock.c#A_Ns_SockAsyncConnect">Ns_SockAsyncConnect</a>(host, i);
487 if (port != NULL) {
488 *port = ':';
489 }
490 if (sock != INVALID_SOCKET) {
491 httpPtr = ns_malloc(sizeof(Http));
492 httpPtr->sock = sock;
493 httpPtr->error = NULL;
494 Tcl_DStringInit(&httpPtr->ds);
495 if (file != NULL) {
496 *file = '/';
497 }
498 <a href="/cvs/aolserver/aolserver/nsd/dstring.c#A_Ns_DStringAppend">Ns_DStringAppend</a>(&httpPtr->ds, method);
499 <a href="/cvs/aolserver/aolserver/nsd/str.c#A_Ns_StrToUpper">Ns_StrToUpper</a>(<a href="/cvs/aolserver/aolserver/nsd/dstring.c#A_Ns_DStringValue">Ns_DStringValue</a>(&httpPtr->ds));
500 <a href="/cvs/aolserver/aolserver/nsd/dstring.c#A_Ns_DStringVarAppend">Ns_DStringVarAppend</a>(&httpPtr->ds, " ", file ? file : "/",
501 " HTTP/1.0\r\n", NULL);
502 if (file != NULL) {
503 *file = '\0';
504 }
505 <a href="/cvs/aolserver/aolserver/nsd/dstring.c#A_Ns_DStringVarAppend">Ns_DStringVarAppend</a>(&httpPtr->ds,
506 "User-Agent: ", <a href="/cvs/aolserver/aolserver/nsd/info.c#A_Ns_InfoServerName">Ns_InfoServerName</a>(), "/",
507 <a href="/cvs/aolserver/aolserver/nsd/info.c#A_Ns_InfoServerVersion">Ns_InfoServerVersion</a>(), "\r\n"
508 "Connection: close\r\n"
509 "Host: ", host, "\r\n", NULL);
510 if (file != NULL) {
511 *file = '/';
512 }
513 if (hdrs != NULL) {
514 for (i = 0; i < Ns_SetSize(hdrs); i++) {
515 <a href="/cvs/aolserver/aolserver/nsd/dstring.c#A_Ns_DStringVarAppend">Ns_DStringVarAppend</a>(&httpPtr->ds,
516 Ns_SetKey(hdrs, i), ": ",
517 Ns_SetValue(hdrs, i), "\r\n", NULL);
518 }
519 }
520 body = NULL;
521 if (bodyPtr != NULL) {
522 body = Tcl_GetByteArrayFromObj(bodyPtr, &len);
523 if (len == 0) {
524 body = NULL;
525 }
526 }
527 if (body != NULL) {
528 <a href="/cvs/aolserver/aolserver/nsd/dstring.c#A_Ns_DStringPrintf">Ns_DStringPrintf</a>(&httpPtr->ds, "Content-Length: %d\r\n", len);
529 }
530 Tcl_DStringAppend(&httpPtr->ds, "\r\n", 2);
531 if (body != NULL) {
532 Tcl_DStringAppend(&httpPtr->ds, body, len);
533 }
534 httpPtr->next = httpPtr->ds.string;
535 httpPtr->len = httpPtr->ds.length;
536 }
537 if (file != NULL) {
538 *file = '/';
539 }
540 if (httpPtr == NULL) {
541 Tcl_AppendResult(interp, "connect to \"", url, "\" failed: ",
542 ns_sockstrerror(ns_sockerrno), NULL);
543 return 0;
544 }
545 *httpPtrPtr = httpPtr;
546 return 1;
547 }
548
549
550 /*
551 *----------------------------------------------------------------------
552 *
553 * <a href="/cvs/aolserver/aolserver/nsd/tclhttp.c#A_HttpResult">HttpResult</a> --
554 *
555 * <a href="/cvs/aolserver/aolserver/nsd/adpparse.c#A_Parse">Parse</a> an Http response for the result body and headers.
556 *
557 * Results:
558 * Pointer to body within Http buffer.
559 *
560 * Side effects:
561 * Will append parsed response headers to given hdrs if
562 * not NULL and set HTTP status code in given statusPtr.
563 *
564 *----------------------------------------------------------------------
565 */
566
567 static char *
568 <a href="/cvs/aolserver/aolserver/nsd/tclhttp.c#A_HttpResult">HttpResult</a>(Tcl_DString ds, int *statusPtr, Ns_Set *hdrs, Tcl_Obj **objPtrPtr)
569 {
570 int firsthdr, major, minor, len;
571 char *eoh, *body, *p, *response, save;
572
573 response = ds.string;
574 body = response;
575 eoh = strstr(response, "\r\n\r\n");
576 if (eoh != NULL) {
577 body = eoh + 4;
578 eoh += 2;
579 } else {
580 eoh = strstr(response, "\n\n");
581 if (eoh != NULL) {
582 body = eoh + 2;
583 eoh += 1;
584 }
585 }
586
587 *objPtrPtr = Tcl_NewByteArrayObj(body, ds.length-(body-response));
588
589 if (eoh == NULL) {
590 *statusPtr = 0;
591 } else {
592 *eoh = '\0';
593 sscanf(response, "HTTP/%d.%d %d", &major, &minor, statusPtr);
594 if (hdrs != NULL) {
595 save = *body;
596 *body = '\0';
597 firsthdr = 1;
598 p = response;
599 while ((eoh = strchr(p, '\n')) != NULL) {
600 *eoh++ = '\0';
601 len = strlen(p);
602 if (len > 0 && p[len-1] == '\r') {
603 p[len-1] = '\0';
604 }
605 if (firsthdr) {
606 if (hdrs->name != NULL) {
607 ns_free(hdrs->name);
608 }
609 hdrs->name = ns_strdup(p);
610 firsthdr = 0;
611 } else if (<a href="/cvs/aolserver/aolserver/nsd/request.c#A_Ns_ParseHeader">Ns_ParseHeader</a>(hdrs, p, ToLower) != NS_OK) {
612 break;
613 }
614 p = eoh;
615 }
616 *body = save;
617 }
618 }
619 return body;
620 }
621
622
623
624 static void
625 <a href="/cvs/aolserver/aolserver/nsd/tclhttp.c#A_HttpClose">HttpClose</a>(Http *httpPtr)
626 {
627 <a href="/cvs/aolserver/aolserver/nsd/task.c#A_Ns_TaskFree">Ns_TaskFree</a>(httpPtr->task);
628 Tcl_DStringFree(&httpPtr->ds);
629 ns_sockclose(httpPtr->sock);
630 ns_free(httpPtr);
631 }
632
633
634 static void
635 <a href="/cvs/aolserver/aolserver/nsd/tclhttp.c#A_HttpCancel">HttpCancel</a>(Http *httpPtr)
636 {
637 <a href="/cvs/aolserver/aolserver/nsd/task.c#A_Ns_TaskCancel">Ns_TaskCancel</a>(httpPtr->task);
638 <a href="/cvs/aolserver/aolserver/nsd/task.c#A_Ns_TaskWait">Ns_TaskWait</a>(httpPtr->task, NULL);
639 }
640
641
642 static void
643 <a href="/cvs/aolserver/aolserver/nsd/tclhttp.c#A_HttpAbort">HttpAbort</a>(Http *httpPtr)
644 {
645 <a href="/cvs/aolserver/aolserver/nsd/tclhttp.c#A_HttpCancel">HttpCancel</a>(httpPtr);
646 <a href="/cvs/aolserver/aolserver/nsd/tclhttp.c#A_HttpClose">HttpClose</a>(httpPtr);
647 }
648
649
650 /*
651 *----------------------------------------------------------------------
652 *
653 * <a href="/cvs/aolserver/aolserver/nsd/tclhttp.c#A_HttpProc">HttpProc</a> --
654 *
655 * Task callback for ns_http connections.
656 *
657 * Results:
658 * None.
659 *
660 * Side effects:
661 * Will call <a href="/cvs/aolserver/aolserver/nsd/task.c#A_Ns_TaskCallback">Ns_TaskCallback</a> and <a href="/cvs/aolserver/aolserver/nsd/task.c#A_Ns_TaskDone">Ns_TaskDone</a> to manage state
662 * of task.
663 *
664 *----------------------------------------------------------------------
665 */
666
667 static void
668 <a href="/cvs/aolserver/aolserver/nsd/tclhttp.c#A_HttpProc">HttpProc</a>(Ns_Task *task, SOCKET sock, void *arg, int why)
669 {
670 Http *httpPtr = arg;
671 char buf[1024];
672 int n;
673
674 switch (why) {
675 case NS_SOCK_INIT:
676 <a href="/cvs/aolserver/aolserver/nsd/task.c#A_Ns_TaskCallback">Ns_TaskCallback</a>(task, NS_SOCK_WRITE, &httpPtr->timeout);
677 return;
678 break;
679
680 case NS_SOCK_WRITE:
681 n = send(sock, httpPtr->next, httpPtr->len, 0);
682 if (n < 0) {
683 httpPtr->error = "send failed";
684 } else {
685 httpPtr->next += n;
686 httpPtr->len -= n;
687 if (httpPtr->len == 0) {
688 shutdown(sock, 1);
689 Tcl_DStringTrunc(&httpPtr->ds, 0);
690 <a href="/cvs/aolserver/aolserver/nsd/task.c#A_Ns_TaskCallback">Ns_TaskCallback</a>(task, NS_SOCK_READ, &httpPtr->timeout);
691 }
692 return;
693 }
694 break;
695
696 case NS_SOCK_READ:
697 n = recv(sock, buf, sizeof(buf), 0);
698 if (n > 0) {
699 Tcl_DStringAppend(&httpPtr->ds, buf, n);
700 return;
701 }
702 if (n < 0) {
703 httpPtr->error = "recv failed";
704 }
705 break;
706
707 case NS_SOCK_TIMEOUT:
708 httpPtr->error = "timeout";
709 break;
710
711 case NS_SOCK_EXIT:
712 httpPtr->error = "shutdown";
713 break;
714
715 case NS_SOCK_CANCEL:
716 httpPtr->error = "cancelled";
717 break;
718 }
719
720 /*
721 * Get completion time and mark task as done.
722 */
723
724 Ns_GetTime(&httpPtr->etime);
725 <a href="/cvs/aolserver/aolserver/nsd/task.c#A_Ns_TaskDone">Ns_TaskDone</a>(httpPtr->task);
726 }