00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "libwww_util.h"
00027 #include "libwww_req.h"
00028 #include "deref.h"
00029 #include "cinterf.h"
00030
00031 int total_number_of_requests = 0;
00032 int event_loop_runnung = FALSE;
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059 DllExport int call_conv do_libwww_request___(void)
00060 {
00061 prolog_term request_term_list = reg_term(1), request_list_tail;
00062 int request_id=0;
00063
00064
00065
00066
00067 HTProfile_newHTMLNoCacheClient("Mozilla", "6.0");
00068
00069
00070
00071
00072 HTAlert_setInteractive(YES);
00073
00074
00075
00076 HTAlert_deleteOpcode(HT_A_PROGRESS);
00077 HTAlert_deleteOpcode(HT_A_MESSAGE);
00078 HTAlert_deleteOpcode(HT_A_CONFIRM);
00079 HTAlert_deleteOpcode(HT_A_PROMPT);
00080 HTAlert_deleteOpcode(HT_A_USER_PW);
00081
00082 HTAlert_add(libwww_send_credentials,HT_A_USER_PW);
00083 HTAlert_add(libwww_send_credentials,HT_A_SECRET);
00084
00085 HTPrint_setCallback(printer);
00086 HTTrace_setCallback(tracer);
00087 #if 0
00088 HTSetTraceMessageMask("sob");
00089 #endif
00090
00091
00092 if (!is_list(request_term_list))
00093 libwww_abort_all("[LIBWWW_REQUEST] Argument must be a list of requests");
00094
00095 request_list_tail = request_term_list;
00096 total_number_of_requests=0;
00097 event_loop_runnung = FALSE;
00098 timeout_value = -1;
00099 while (is_list(request_list_tail) && !is_nil(request_list_tail)) {
00100 request_id++;
00101 total_number_of_requests++;
00102 setup_request_structure(p2p_car(request_list_tail), request_id);
00103 request_list_tail = p2p_cdr(request_list_tail);
00104 }
00105
00106 if (timeout_value <= 0)
00107 timeout_value = DEFAULT_TIMEOUT;
00108
00109
00110 if (total_number_of_requests > 0) {
00111
00112 HTTimer* timer = HTTimer_new(NULL, timer_cbf, NULL, 2*timeout_value, 1, 1);
00113
00114 #ifdef LIBWWW_DEBUG
00115 xsb_dbgmsg((LOG_DEBUG,"***In libwww_request: Starting event loop. Total requests=%d, timeout=%d",
00116 total_number_of_requests, timeout_value));
00117 #endif
00118
00119 HTTimer_dispatch(timer);
00120
00121 event_loop_runnung = TRUE;
00122 HTEventList_newLoop();
00123
00124
00125
00126 event_loop_runnung = FALSE;
00127
00128
00129
00130 #ifdef LIBWWW_DEBUG
00131 xsb_dbgmsg((LOG_DEBUG,"***Expiring timers"));
00132 #endif
00133 HTTimer_expireAll();
00134 HTTimer_delete(timer);
00135
00136 #ifdef LIBWWW_DEBUG
00137 xsb_dbgmsg((LOG_DEBUG,"***In libwww_request: event loop ended: total outstanding requests=%d", total_number_of_requests));
00138 #endif
00139 }
00140
00141
00142
00143 HTProfile_delete();
00144 return TRUE;
00145 }
00146
00147
00148
00149
00150
00151 PRIVATE void setup_request_structure(prolog_term req_term, int request_id)
00152 {
00153 int status;
00154 HTAnchor *anchor = NULL;
00155 HTRequest *request=NULL;
00156 HTAssocList *formdata=NULL;
00157 char *uri = NULL;
00158 char *cwd = HTGetCurrentDirectoryURL();
00159 REQUEST_CONTEXT *context;
00160
00161
00162 request=HTRequest_new();
00163 context=set_request_context(request,req_term,request_id);
00164 setup_termination_filter(request, request_termination_handler);
00165 setup_callbacks(context->type);
00166
00167 uri = extract_uri(req_term,request, request_id);
00168
00169 get_request_params(req_term, request);
00170
00171
00172
00173 if (timeout_value <= 0 && context->timeout > 0) {
00174 timeout_value = context->timeout;
00175 HTHost_setEventTimeout(timeout_value);
00176 }
00177
00178 formdata = (context->formdata ?
00179 get_form_params(context->formdata,request_id) : NULL);
00180
00181 uri = HTParse(uri, cwd, PARSE_ALL);
00182
00183 anchor = HTAnchor_findAddress(uri);
00184
00185
00186 if (strncmp(uri,"file:/",6) == 0)
00187 HTRequest_setPreemptive(request,YES);
00188
00189
00190 if ((context->type != HEADER) && (context->user_modtime > 0)) {
00191 HTRequest *header_req = HTRequest_new();
00192 context->is_subrequest = TRUE;
00193 context->subrequest_id++;
00194 setup_termination_filter(header_req,handle_dependent_termination);
00195 HTRequest_setPreemptive(header_req, YES);
00196
00197
00198
00199
00200 HTRequest_setContext(header_req, (void *)context);
00201 HTHeadAnchor(anchor,header_req);
00202 context->last_modtime = HTAnchor_lastModified((HTParentAnchor *)anchor);
00203
00204 if (context->user_modtime > context->last_modtime) {
00205
00206 #ifdef LIBWWW_DEBUG
00207 xsb_dbgmsg((LOG_DEBUG,"***Request %s: Page older(%d) than if-modified-since time(%d)",
00208 RequestID(request),
00209 context->last_modtime, context->user_modtime));
00210 #endif
00211
00212 total_number_of_requests--;
00213
00214 if (is_var(context->status_term)) {
00215 if (context->last_modtime <= 0)
00216 c2p_int(HT_ERROR, context->status_term);
00217 else
00218 c2p_int(WWW_EXPIRED_DOC, context->status_term);
00219 } else
00220 libwww_abort_all("[LIBWWW_REQUEST] Request %s: Arg 5 (Status) must be unbound variable",
00221 RequestID(request));
00222
00223 extract_request_headers(header_req);
00224
00225 c2p_nil(context->result_params);
00226
00227 release_libwww_request(request);
00228 HT_FREE(uri);
00229 return;
00230 }
00231 }
00232
00233
00234 switch (context->type) {
00235 case HEADER:
00236
00237
00238 HTRequest_setPreemptive(request, YES);
00239 status = (YES == HTHeadAnchor(anchor,request));
00240 break;
00241 case FETCH:
00242 {
00243 HTStream *target;
00244 HTRequest_setOutputFormat(request, WWW_SOURCE);
00245
00246 target = HTStreamToChunk(request, &(context->result_chunk), 0);
00247 HTRequest_setOutputStream(request, target);
00248
00249 goto LBLREQUEST;
00250 }
00251 case XMLPARSE:
00252
00253
00254
00255
00256 set_xml_conversions();
00257 HTRequest_setConversion(request, XML_converter, YES);
00258
00259
00260
00261
00262 HTRequest_setOutputFormat(request, HTAtom_for("www/xml"));
00263 goto LBLREQUEST;
00264 case RDFPARSE:
00265
00266
00267 set_rdf_conversions();
00268 HTRequest_setConversion(request, RDF_converter, YES);
00269 HTRequest_setOutputFormat(request, HTAtom_for("www/rdf"));
00270 goto LBLREQUEST;
00271 case HTMLPARSE:
00272
00273
00274 set_html_conversions();
00275 HTRequest_setConversion(request, HTML_converter, YES);
00276 HTRequest_setOutputFormat(request, HTAtom_for("www/html"));
00277 goto LBLREQUEST;
00278 LBLREQUEST:
00279 if (formdata) {
00280 if (context->method == METHOD_GET)
00281 status = (YES == HTGetFormAnchor(formdata,anchor,request));
00282 else if (context->method == METHOD_POST)
00283 status = (NULL != HTPostFormAnchor(formdata,anchor,request));
00284 } else {
00285
00286 status = (YES==HTLoadAnchor(anchor, request));
00287 }
00288 break;
00289 default:
00290 libwww_abort_all("[LIBWWW_REQUEST] Request %d: Invalid request type",
00291 request_id);
00292 }
00293
00294 #ifdef LIBWWW_DEBUG_TERSE
00295 switch (context->type) {
00296 case HTMLPARSE:
00297 xsb_dbgmsg((LOG_DEBUG,"***Request %d: request type: htmlparse", request_id));
00298 break;
00299 case XMLPARSE:
00300 xsb_dbgmsg((LOG_DEBUG,"***Request %d: request type: xmlparse", request_id));
00301 break;
00302 case RDFPARSE:
00303 xsb_dbgmsg((LOG_DEBUG,"***Request %d: request type: rdfparse", request_id));
00304 break;
00305 case HEADER:
00306 xsb_dbgmsg((LOG_DEBUG,"***Request %d: request type: header", request_id));
00307 break;
00308 case FETCH:
00309 xsb_dbgmsg((LOG_DEBUG,"***Request %d: request type: fetch", request_id));
00310 break;
00311 default:
00312 xsb_dbgmsg((LOG_DEBUG,"***Request %d: request type: invalid", request_id));
00313 }
00314 if (formdata)
00315 xsb_dbgmsg((LOG_DEBUG,"***Request %d: HTTP Method: %s, preemptive: %d",
00316 request_id,
00317 (context->method==METHOD_GET ? "FORM,GET" : "FORM,POST"),
00318 HTRequest_preemptive(request)));
00319 else
00320 xsb_dbgmsg((LOG_DEBUG,"***Request %d: HTTP Method: NON-FORM REQ, preemptive: %d",
00321 request_id, HTRequest_preemptive(request)));
00322 #endif
00323
00324 if (formdata) HTAssocList_delete(formdata);
00325
00326
00327 if (!status) {
00328 #ifdef LIBWWW_DEBUG
00329 xsb_dbgmsg((LOG_DEBUG,"***In setup_request_structure: Request %d failed: bad uri",
00330 request_id));
00331 #endif
00332 total_number_of_requests--;
00333 if (is_var(context->status_term))
00334 c2p_int(WWW_URI_SYNTAX, context->status_term);
00335 else
00336 libwww_abort_all("[LIBWWW_REQUEST] Request %s: Arg 5 (Status) must be unbound variable",
00337 RequestID(request));
00338
00339 c2p_nil(context->result_params);
00340 release_libwww_request(request);
00341 }
00342 HT_FREE(uri);
00343 }
00344
00345
00346
00347
00348
00349
00350
00351 PRIVATE int handle_dependent_termination(HTRequest *request,
00352 HTResponse *response,
00353 void *param,
00354 int status)
00355 {
00356 REQUEST_CONTEXT *context = (REQUEST_CONTEXT *)HTRequest_context(request);
00357 #ifdef LIBWWW_DEBUG
00358 xsb_dbgmsg((LOG_DEBUG,"***In handle_dependent_termination(%s): user_modtime=%d status=%d",
00359 RequestID(request), context->user_modtime, status));
00360 #endif
00361
00362
00363 if (context->retry && AUTH_OR_REDIRECTION(status))
00364 return HT_OK;
00365
00366 if (status != HT_LOADED)
00367 report_synch_subrequest_status(request, status);
00368
00369
00370
00371 HTRequest_clear(request);
00372
00373 context->is_subrequest = FALSE;
00374 return !HT_OK;
00375 }
00376
00377
00378
00379 PRIVATE void libwww_abort_all(char *msg, ...)
00380 {
00381 va_list args;
00382 char buf[MAXBUFSIZE];
00383
00384 HTNet_killAll();
00385 va_start(args, msg);
00386 vsprintf(buf, msg, args);
00387 xsb_abort(buf);
00388 va_end(args);
00389 }
00390
00391
00392 void report_synch_subrequest_status(HTRequest *request, int status)
00393 {
00394 prolog_term uri_term=p2p_new(), error_term=p2p_new();
00395 REQUEST_CONTEXT *context = (REQUEST_CONTEXT *)HTRequest_context(request);
00396 char *uri = HTAnchor_physical(HTRequest_anchor(request));
00397 c2p_string(uri,uri_term);
00398 c2p_int(status, error_term);
00399 add_result_param(&(context->result_params),
00400 "subrequest",2,uri_term,error_term);
00401 }
00402
00403
00404 void report_asynch_subrequest_status(HTRequest *request, int status)
00405 {
00406 REQUEST_CONTEXT *context = (REQUEST_CONTEXT *)HTRequest_context(request);
00407 char *uri = HTAnchor_physical(HTRequest_anchor(request));
00408
00409 c2p_functor("subrequest",2,context->result_params);
00410 c2p_string(uri,p2p_arg(context->result_params,1));
00411 c2p_int(status, p2p_arg(context->result_params,2));
00412 }
00413
00414
00415 PRIVATE REQUEST_CONTEXT *set_request_context(HTRequest *request,
00416 prolog_term req_term,
00417 int request_id)
00418 {
00419 REQUEST_CONTEXT *context;
00420
00421 if ((context=(REQUEST_CONTEXT *)calloc(1,sizeof(REQUEST_CONTEXT))) == NULL)
00422 libwww_abort_all("[LIBWWW_REQUEST] Not enough memory");
00423
00424 context->request_id = request_id;
00425 context->subrequest_id = 0;
00426 context->suppress_is_default = FALSE;
00427 context->convert2list = FALSE;
00428 context->statusOverride = 0;
00429 context->is_subrequest = FALSE;
00430 context->userdata = NULL;
00431 context->last_modtime = 0;
00432 context->timeout = DEFAULT_TIMEOUT;
00433 context->user_modtime = 0;
00434 context->formdata=0;
00435 context->auth_info.realm = "";
00436 context->auth_info.uid = "foo";
00437 context->auth_info.pw = "foo";
00438 context->retry = TRUE;
00439 context->method = METHOD_GET;
00440 context->selected_tags_tbl.table = NULL;
00441 context->suppressed_tags_tbl.table = NULL;
00442 context->stripped_tags_tbl.table = NULL;
00443
00444 context->type = get_request_type(req_term, request_id);
00445 context->result_chunk = NULL;
00446
00447 init_htable(&(context->selected_tags_tbl),
00448 SELECTED_TAGS_TBL_SIZE,context->type);
00449 init_htable(&(context->suppressed_tags_tbl),
00450 SUPPRESSED_TAGS_TBL_SIZE,context->type);
00451 init_htable(&(context->stripped_tags_tbl),
00452 STRIPPED_TAGS_TBL_SIZE,context->type);
00453
00454 context->result_params = p2p_arg(req_term,3);
00455 if(!is_var(context->result_params))
00456 libwww_abort_all("[LIBWWW_REQUEST] Request %d: Arg 3 (Result parameters) must be unbound variable", request_id);
00457 c2p_list(context->result_params);
00458
00459 context->request_result = p2p_arg(req_term,4);
00460 if(!is_var(context->request_result))
00461 libwww_abort_all("[LIBWWW_REQUEST] Request %d: Arg 4 (Result) must be unbound variable", request_id);
00462
00463 context->status_term = p2p_arg(req_term,5);
00464 if(!is_var(context->status_term))
00465 libwww_abort_all("[LIBWWW_REQUEST] Request %d: Arg 5 (Status) must be unbound variable", request_id);
00466
00467
00468 HTRequest_setContext(request, (void *) context);
00469
00470 #ifdef LIBWWW_DEBUG
00471 xsb_dbgmsg((LOG_DEBUG,"***Request %d: context set", request_id));
00472 #endif
00473
00474 return context;
00475 }
00476
00477
00478 PRIVATE void free_request_context (REQUEST_CONTEXT *context)
00479 {
00480 AUTHENTICATION *next_auth, *curr_auth;
00481 if (!context) return;
00482 free_htable(&(context->selected_tags_tbl));
00483 free_htable(&(context->suppressed_tags_tbl));
00484 free_htable(&(context->stripped_tags_tbl));
00485
00486
00487
00488
00489 if (!(context->is_subrequest)) {
00490 next_auth = context->auth_info.next;
00491 while (next_auth) {
00492 curr_auth = next_auth;
00493 next_auth=next_auth->next;
00494 free(curr_auth);
00495 }
00496 }
00497 free(context);
00498 }
00499
00500
00501
00502 void strcpy_lower(char *to, const char *from)
00503 {
00504 int i=0;
00505 if (from)
00506 while (from[i]) {
00507 to[i] = tolower(from[i]);
00508 i++;
00509 }
00510 to[i] = '\0';
00511 }
00512
00513
00514 void print_prolog_term(prolog_term term, char *message)
00515 {
00516 static XSB_StrDefine(StrArgBuf);
00517 prolog_term term2 = p2p_deref(term);
00518 XSB_StrSet(&StrArgBuf,"");
00519 print_pterm(term2, 1, &StrArgBuf);
00520 #ifdef LIBWWW_DEBUG
00521 xsb_dbgmsg((LOG_DEBUG,"***%s = %s", message, StrArgBuf.string));
00522 #endif
00523 }
00524
00525
00526
00527 PRIVATE int printer (const char * fmt, va_list pArgs)
00528 {
00529 return (vfprintf(stdout, fmt, pArgs));
00530 }
00531
00532 PRIVATE int tracer (const char * fmt, va_list pArgs)
00533 {
00534 return (vfprintf(stderr, fmt, pArgs));
00535 }
00536
00537
00538
00539
00540
00541 BOOL libwww_send_credentials(HTRequest * request, HTAlertOpcode op,
00542 int msgnum, const char * dfault, void * realm,
00543 HTAlertPar * reply)
00544 {
00545 REQUEST_CONTEXT *context = (REQUEST_CONTEXT *)HTRequest_context(request);
00546 AUTHENTICATION *authinfo = &(context->auth_info);
00547 AUTHENTICATION *credentials;
00548
00549 #ifdef LIBWWW_DEBUG
00550 xsb_dbgmsg((LOG_DEBUG,"***In libwww_send_credentials: Request=%s, realm: '%s' msgnum=%d",
00551 RequestID(request), realm, msgnum));
00552 #endif
00553
00554
00555 context->retry = FALSE;
00556
00557 credentials = find_credentials(authinfo,realm);
00558 if (credentials) {
00559
00560 HTAlert_setReplyMessage(reply, credentials->uid);
00561 HTAlert_setReplySecret(reply, credentials->pw);
00562 return TRUE;
00563 }
00564
00565 HTAlert_setReplyMessage(reply, "foo");
00566 HTAlert_setReplySecret(reply, "foo");
00567 return TRUE;
00568 }
00569
00570
00571 PRIVATE AUTHENTICATION *find_credentials(AUTHENTICATION *auth_info,char *realm)
00572 {
00573 AUTHENTICATION *credentials = auth_info;
00574
00575 while (credentials) {
00576 if ((credentials->realm == NULL)
00577 || (strcmp(credentials->realm, realm) == 0))
00578 return credentials;
00579 credentials = credentials->next;
00580 }
00581 return NULL;
00582 }
00583
00584
00585 PRIVATE char *extract_uri(prolog_term req_term, HTRequest *request,
00586 int request_id)
00587 {
00588
00589
00590
00591 int urilen;
00592 char *uri;
00593 prolog_term uri_term;
00594
00595 uri_term=p2p_arg(req_term,1);
00596 if (is_charlist(uri_term, &urilen)) {
00597 ((REQUEST_CONTEXT *)HTRequest_context(request))->convert2list=TRUE;
00598
00599
00600
00601
00602 p2c_chars(uri_term, uri, urilen);
00603 } else if (is_string(uri_term))
00604 uri=string_val(uri_term);
00605 else {
00606 release_libwww_request(request);
00607
00608 libwww_abort_all("[LIBWWW_REQUEST] Request %d: Arg 1 (URI) must be an atom or a string", request_id);
00609 }
00610 return uri;
00611 }
00612
00613
00614 PRIVATE void release_libwww_request(HTRequest *request)
00615 {
00616 free_request_context((REQUEST_CONTEXT *) HTRequest_context(request));
00617 HTRequest_kill(request);
00618 }
00619
00620
00621
00622 PRIVATE void get_request_params(prolog_term req_term, HTRequest *request)
00623 {
00624 prolog_term param, req_params=p2p_arg(req_term,2);
00625 char *paramfunctor;
00626 REQUEST_CONTEXT *context = (REQUEST_CONTEXT *)HTRequest_context(request);
00627
00628 if (!is_list(req_params) && !is_var(req_params) && !is_nil(req_params))
00629 libwww_abort_all("[LIBWWW_REQUEST] Request %s: Arg 2 (Request params) must be a list or a variable",
00630 RequestID(request));
00631 while(is_list(req_params) && !is_nil(req_params)) {
00632 param = p2p_car(req_params);
00633 paramfunctor = p2c_functor(param);
00634
00635 switch (paramfunctor[0]) {
00636 case 't': case 'T':
00637 if (!is_int(p2p_arg(param, 1)))
00638 libwww_abort_all("[LIBWWW_REQUEST] Request %s: Timeout parameter must be an integer",
00639 RequestID(request));
00640 context->timeout = p2c_int(p2p_arg(param, 1)) * 1000;
00641 if (context->timeout <= 0)
00642 context->timeout = DEFAULT_TIMEOUT;
00643 break;
00644 case 'i': case 'I':
00645 if (!is_string(p2p_arg(param, 1)))
00646 libwww_abort_all("[LIBWWW_REQUEST] Request %s: If_modified_since parameter must be a string",
00647 RequestID(request));
00648 context->user_modtime =
00649 (long)HTParseTime(string_val(p2p_arg(param,1)), NULL, YES);
00650 break;
00651 case 'a': case 'A': {
00652 prolog_term auth_head, auth_tail=p2p_arg(param,1);
00653 AUTHENTICATION *auth_info = &(context->auth_info);
00654
00655 do {
00656 if (is_list(auth_tail)) {
00657 auth_head=p2p_car(auth_tail);
00658 auth_tail=p2p_cdr(auth_tail);
00659 } else auth_head = auth_tail;
00660
00661 if (is_string(p2p_arg(auth_head, 1)))
00662 auth_info->realm = p2c_string(p2p_arg(auth_head, 1));
00663 else auth_info->realm = NULL;
00664 if (is_string(p2p_arg(auth_head, 2)))
00665 auth_info->uid = p2c_string(p2p_arg(auth_head, 2));
00666 else auth_info->uid = NULL;
00667
00668 if (is_string(p2p_arg(auth_head, 3)))
00669 auth_info->pw = p2c_string(p2p_arg(auth_head, 3));
00670 else auth_info->pw = NULL;
00671
00672 if (is_list(auth_tail) && !is_nil(auth_tail)) {
00673 auth_info->next = (AUTHENTICATION *)calloc(1,sizeof(AUTHENTICATION));
00674 auth_info = auth_info->next;
00675 } else break;
00676
00677 } while (TRUE);
00678 auth_info->next=NULL;
00679 break;
00680 }
00681 case 'f': case 'F':
00682 context->formdata = p2p_arg(param, 1);
00683 break;
00684 case 'm': case 'M': {
00685 char *method = p2c_string(p2p_arg(param, 1));
00686 switch (method[1]) {
00687 case 'O': case 'o':
00688 context->method = METHOD_POST;
00689 break;
00690 case 'E': case 'e':
00691 context->method = METHOD_GET;
00692 break;
00693 case 'P': case 'p':
00694 context->method = METHOD_PUT;
00695 break;
00696 }
00697 break;
00698 }
00699 case 's': case 'S':
00700
00701 if (p2c_arity(param)==3) {
00702 prolog_term
00703 select_term=p2p_arg(param,1),
00704 suppressed_term=p2p_arg(param,2),
00705 strip_term=p2p_arg(param,3);
00706
00707 if (is_var(select_term))
00708 context->suppress_is_default=FALSE;
00709 else if (is_list(select_term)) {
00710 context->suppress_is_default=TRUE;
00711 init_tag_table(select_term, &(context->selected_tags_tbl));
00712 } else
00713 libwww_abort_all("[LIBWWW_REQUEST] Request %d: In Arg 2, selection(CHOOSE,_,_): CHOOSE must be a var or a list");
00714
00715 if (is_list(suppressed_term)) {
00716 init_tag_table(suppressed_term, &(context->suppressed_tags_tbl));
00717 } else if (!is_var(suppressed_term))
00718 libwww_abort_all("[LIBWWW_REQUEST] Request %s: In Arg 2, selection(_,SUPPRESS,_): SUPPRESS must be a var or a list",
00719 RequestID(request));
00720
00721 if (is_list(strip_term)) {
00722 init_tag_table(strip_term, &(context->stripped_tags_tbl));
00723 } else if (!is_var(strip_term))
00724 libwww_abort_all("[LIBWWW_REQUEST] Request %s: In Arg 2, selection(_,_,STRIP): STRIP must be a var or a list",
00725 RequestID(request));
00726 } else {
00727 libwww_abort_all("[LIBWWW_REQUEST] Request %s: In Arg 2, wrong number of arguments in selection parameter",
00728 RequestID(request));
00729 }
00730 break;
00731 default:
00732 break;
00733 }
00734 req_params = p2p_cdr(req_params);
00735 }
00736 return;
00737 }
00738
00739
00740
00741 PRIVATE HTAssocList *get_form_params(prolog_term form_params, int request_id)
00742 {
00743 HTAssocList *formfields=NULL;
00744
00745 if (!is_list(form_params))
00746 libwww_abort_all("[LIBWWW_REQUEST] Request %d: List of form parameters must not be empty",
00747 request_id);
00748
00749 while (!is_nil(form_params)) {
00750 prolog_term head;
00751 char *string;
00752
00753 head = p2p_car(form_params);
00754 if (is_string(head))
00755 string = p2c_string(head);
00756 else
00757 libwww_abort_all("[LIBWWW_REQUEST] Request %d: Non-string in form parameter list",
00758 request_id);
00759
00760 form_params = p2p_cdr(form_params);
00761
00762
00763 if (!formfields) formfields = HTAssocList_new();
00764
00765
00766 HTParseFormInput(formfields, string);
00767 }
00768 return formfields;
00769 }
00770
00771
00772 PRIVATE REQUEST_TYPE get_request_type(prolog_term req_term, int request_id)
00773 {
00774 char *functor;
00775 if (!is_functor(req_term)) {
00776 libwww_abort_all("[LIBWWW_REQUEST] Request %d: Bad request syntax",
00777 request_id);
00778 }
00779 functor = p2c_functor(req_term);
00780
00781 if (strncmp("fetch",functor,3)==0) return FETCH;
00782 if (strncmp("xmlparse",functor,3)==0) return XMLPARSE;
00783 if (strncmp("rdfparse",functor,3)==0) return RDFPARSE;
00784 if (strncmp("htmlparse",functor,3)==0) return HTMLPARSE;
00785 if (strncmp("header",functor,3)==0) return HEADER;
00786 libwww_abort_all("[LIBWWW_REQUEST] Request %d: Invalid request type: %s",
00787 request_id, functor);
00788 return TRUE;
00789 }
00790
00791
00792 PRIVATE void init_htable(HASH_TABLE *htable, int size, REQUEST_TYPE type)
00793 {
00794 int i;
00795
00796 if ((type != XMLPARSE) && (type != HTMLPARSE)) {
00797 htable->table = NULL;
00798 return;
00799 }
00800
00801 htable->type = type;
00802 htable->size = size;
00803 if ((htable->table=(HKEY *)calloc(size, sizeof(HKEY))) == NULL )
00804 libwww_abort_all("[LIBWWW_REQUEST] Not enough memory");
00805 for (i=0; i<size; i++)
00806 if (type == HTMLPARSE)
00807 htable->table[i].intkey = -1;
00808 else
00809 htable->table[i].strkey = NULL;
00810 }
00811
00812
00813 PRIVATE void free_htable(HASH_TABLE *htable)
00814 {
00815 if (!htable || !htable->table) return;
00816 if (htable->type == HTMLPARSE) {
00817 free(htable->table);
00818 } else if (htable->type == XMLPARSE) {
00819 int i;
00820 if (!htable) return;
00821 for (i=0; i < htable->size; i++)
00822 if (htable->table[i].strkey != NULL)
00823 free(htable->table[i].strkey);
00824 free(htable->table);
00825 } else return;
00826 }
00827
00828
00829 PRIVATE unsigned long key2int(HKEY s, REQUEST_TYPE type)
00830 {
00831 if (type == HTMLPARSE)
00832 return s.intkey;
00833 else if (type == XMLPARSE) {
00834 unsigned long h = 0;
00835 while (*(s.strkey))
00836 h = (h << 5) + h + (unsigned char)*(s.strkey)++;
00837 return h;
00838 }
00839 return 0;
00840 }
00841
00842
00843 #define FREE_CELL(hkey,type) \
00844 (type==HTMLPARSE ? (hkey.intkey==-1) : (hkey.strkey==NULL))
00845
00846 int add_to_htable(HKEY item, HASH_TABLE *htable)
00847 {
00848 int idx, i;
00849 if (!htable || !htable->table) return FALSE;
00850
00851 idx = (int) (key2int(item, htable->type) % htable->size);
00852 i = idx;
00853 while (!FREE_CELL(htable->table[i], htable->type)) {
00854 i++;
00855 i = i % htable->size;
00856 if (i == idx)
00857 return FALSE;
00858 }
00859
00860 if (htable->type==HTMLPARSE)
00861 htable->table[i].intkey = item.intkey;
00862 else {
00863 htable->table[i].strkey = (char *)malloc(strlen(item.strkey)+1);
00864 strcpy_lower(htable->table[i].strkey, item.strkey);
00865 }
00866 return TRUE;
00867 }
00868
00869
00870 #define HASH_CELL_EQUAL(cell,item,type) \
00871 (type==HTMLPARSE ? (cell.intkey==item.intkey) \
00872 : (cell.strkey && strcasecmp(cell.strkey,item.strkey)==0))
00873
00874
00875 int is_in_htable(const HKEY item, HASH_TABLE *htable)
00876 {
00877 int idx, i;
00878 if (!htable || !htable->table) return FALSE;
00879
00880 idx = (int) (key2int(item,htable->type) % htable->size);
00881 i = idx;
00882 while (!FREE_CELL(htable->table[i], htable->type)) {
00883 if (HASH_CELL_EQUAL(htable->table[i], item, htable->type)) {
00884 return TRUE;
00885 }
00886 i++;
00887 i = i % htable->size;
00888 if (i == idx)
00889 return FALSE;
00890 }
00891 return FALSE;
00892 }
00893
00894
00895
00896 PRIVATE int request_termination_handler (HTRequest *request,
00897 HTResponse *response,
00898 void *param,
00899 int status)
00900 {
00901 REQUEST_CONTEXT *context = ((REQUEST_CONTEXT *)HTRequest_context(request));
00902 USERDATA *userdata = (USERDATA *)(context->userdata);
00903
00904 #ifdef LIBWWW_DEBUG
00905 xsb_dbgmsg((LOG_DEBUG,"***Request %s: In request_termination_handler, status %d",
00906 RequestID(request), status));
00907 #endif
00908
00909
00910 if (context->retry && AUTH_OR_REDIRECTION(status))
00911 return HT_OK;
00912
00913
00914
00915 #if 0
00916 if (status == HT_TEMP_REDIRECT || status == HT_PERM_REDIRECT ||
00917 status == HT_FOUND || status == HT_SEE_OTHER) {
00918 HTAnchor *redirection = HTResponse_redirection(response);
00919
00920
00921
00922 if (YES==HTLoadAnchor(redirection,request))
00923 return !HT_OK;
00924 }
00925 #endif
00926
00927 if (total_number_of_requests > 0)
00928 total_number_of_requests--;
00929
00930 if ((total_number_of_requests == 0) && event_loop_runnung) {
00931 HTEventList_stopLoop();
00932 event_loop_runnung = FALSE;
00933 #ifdef LIBWWW_DEBUG
00934 xsb_dbgmsg((LOG_DEBUG,"***In request_termination_handler: event loop halted, status=%d, HTNetCount=%d",
00935 status, HTNet_count()));
00936 #endif
00937 }
00938
00939 status = (context->statusOverride ? context->statusOverride : status);
00940 if (userdata)
00941 userdata->status = status;
00942
00943 if (is_var(context->status_term))
00944 c2p_int(status, context->status_term);
00945
00946 extract_request_headers(request);
00947
00948 c2p_nil(context->result_params);
00949
00950
00951 if (userdata) {
00952 (userdata->delete_method)(userdata);
00953 } else if (context->type == FETCH) {
00954 char *result_as_string = HTChunk_toCString(context->result_chunk);
00955
00956 if (!is_var(context->request_result))
00957 libwww_abort_all("[LIBWWW_REQUEST] Request %s: Arg 4 (Result) must be unbound variable",
00958 RequestID(request));
00959
00960 if (result_as_string) {
00961 if (context->convert2list)
00962 c2p_chars(result_as_string, context->request_result);
00963 else c2p_string(result_as_string, context->request_result);
00964 }
00965
00966
00967 HT_FREE(result_as_string);
00968 }
00969
00970 #ifdef LIBWWW_DEBUG
00971 xsb_dbgmsg((LOG_DEBUG,"***In request_termination_handler: Cleanup: request %s, status=%d remaining requests: %d",
00972 RequestID(request), status, total_number_of_requests));
00973 #endif
00974
00975 release_libwww_request(request);
00976
00977
00978 return !HT_OK;
00979 }
00980
00981
00982 PRIVATE void setup_callbacks(REQUEST_TYPE type)
00983 {
00984 switch (type) {
00985 case HTMLPARSE:
00986 html_register_callbacks();
00987 break;
00988 case XMLPARSE:
00989
00990 HTXMLCallback_registerNew(HTXML_newInstance, NULL);
00991 break;
00992 case RDFPARSE:
00993 HTRDF_registerNewParserCallback(libwww_newRDF_parserHandler, NULL);
00994 break;
00995 case FETCH:
00996 break;
00997 case HEADER:
00998 break;
00999 }
01000 }
01001
01002
01003 PRIVATE void init_tag_table(prolog_term tag_list, HASH_TABLE *tag_tbl)
01004 {
01005 prolog_term tail, head;
01006 int i=0;
01007 char *tagname;
01008 HKEY taghandle;
01009 if ((tag_tbl->type != XMLPARSE) && (tag_tbl->type != HTMLPARSE))
01010 return;
01011
01012 tail=tag_list;
01013 while (is_list(tail) && !is_nil(tail) && i < tag_tbl->size) {
01014 head= p2p_car(tail);
01015 tail=p2p_cdr(tail);
01016 tagname = string_val(head);
01017 if (tag_tbl->type == XMLPARSE)
01018 taghandle = (HKEY)tagname;
01019 else
01020 taghandle = (HKEY)(strcasecmp(tagname,"pcdata")==0?
01021 PCDATA_SPECIAL
01022 : SGML_findElementNumber(HTML_dtd(), tagname));
01023 add_to_htable(taghandle, tag_tbl);
01024 i++;
01025 }
01026 }
01027
01028
01029
01030
01031
01032 void add_result_param(prolog_term *result_param,
01033 char *functor, int cnt, ...)
01034 {
01035 prolog_term listHead;
01036 int i;
01037 va_list ap;
01038
01039 #ifdef LIBWWW_DEBUG_VERBOSE
01040 xsb_dbgmsg((LOG_DEBUG,"***Starting add_result_param"));
01041 #endif
01042
01043 XSB_Deref(*result_param);
01044 if (is_list(*result_param))
01045 listHead = p2p_car(*result_param);
01046 else {
01047 print_prolog_term(*result_param, "In add_result_param: result_param");
01048 libwww_abort_all("[LIBWWW_REQUEST] Bug: result_param is not a list");
01049 }
01050 c2p_functor(functor, cnt, listHead);
01051 va_start(ap,cnt);
01052 for (i=0; i<cnt; i++)
01053 p2p_unify(va_arg(ap, prolog_term), p2p_arg(listHead, i+1));
01054 va_end(ap);
01055
01056 #ifdef LIBWWW_DEBUG_VERBOSE
01057 print_prolog_term(listHead, "In add_result_param: listHead");
01058 #endif
01059 *result_param = p2p_cdr(*result_param);
01060 c2p_list(*result_param);
01061 }
01062
01063
01064
01065
01066 PRIVATE prolog_term get_result_param_stub(prolog_term *result_param)
01067 {
01068 prolog_term listHead;
01069
01070 XSB_Deref(*result_param);
01071 if (is_list(*result_param))
01072 listHead = p2p_car(*result_param);
01073 else {
01074 print_prolog_term(*result_param, "In get_result_param_stub: result_param");
01075 libwww_abort_all("[LIBWWW_REQUEST] Bug: result_param is not a list");
01076 }
01077 *result_param = p2p_cdr(*result_param);
01078 c2p_list(*result_param);
01079 return listHead;
01080 }
01081
01082
01083
01084
01085 PRIVATE void extract_request_headers(HTRequest *request)
01086 {
01087 HTParentAnchor * anchor;
01088 HTAssocList * headers;
01089 prolog_term paramvalue_term=p2p_new(), paramname_term=p2p_new();
01090 REQUEST_CONTEXT *context = (REQUEST_CONTEXT *)HTRequest_context(request);
01091
01092 anchor = HTRequest_anchor(request);
01093 headers = HTAnchor_header(anchor);
01094 if (headers) {
01095 HTAssocList *cur = headers;
01096 HTAssoc *pres;
01097 char *paramname, *paramvalue;
01098
01099 while ((pres = (HTAssoc *) HTAssocList_nextObject(cur))) {
01100 paramname = HTAssoc_name(pres);
01101 paramvalue = HTAssoc_value(pres);
01102 c2p_string(paramvalue, paramvalue_term);
01103 c2p_string(paramname, paramname_term);
01104
01105 add_result_param(&(context->result_params),
01106 "header",2,paramname_term,paramvalue_term);
01107
01108
01109 if (HTStrCaseMatch("Last-Modified", paramname))
01110 context->last_modtime = (long)HTParseTime(paramvalue,NULL,YES);
01111 }
01112 }
01113 }
01114
01115
01116 PRIVATE int timer_cbf(HTTimer *timer, void *param, HTEventType type)
01117 {
01118 return !HT_OK;
01119 }
01120
01121
01122 int verifyMIMEformat(HTRequest *request, REQUEST_TYPE type)
01123 {
01124 if (((REQUEST_CONTEXT *)HTRequest_context(request))->type == type)
01125 return TRUE;
01126
01127
01128
01129
01130 return FALSE;
01131 }
01132
01133
01134 char *RequestID(HTRequest *request)
01135 {
01136 REQUEST_CONTEXT *context = (REQUEST_CONTEXT *)HTRequest_context(request);
01137 static char idstr[200];
01138
01139 if (!context) return "null";
01140
01141 if (context->is_subrequest)
01142 sprintf(idstr, "%d.%d", context->request_id, context->subrequest_id);
01143 else
01144 sprintf(idstr, "%d", context->request_id);
01145
01146 return idstr;
01147 }
01148
01149
01150 REQUEST_CONTEXT *set_subrequest_context(HTRequest *request,
01151 HTRequest *subrequest,
01152 prolog_term result_term)
01153 {
01154 REQUEST_CONTEXT *parent_context =
01155 (REQUEST_CONTEXT *)HTRequest_context(request);
01156 REQUEST_CONTEXT *context;
01157 HTStream *target;
01158
01159 if ((context=(REQUEST_CONTEXT *)calloc(1,sizeof(REQUEST_CONTEXT))) == NULL)
01160 libwww_abort_all("[LIBWWW_REQUEST] Not enough memory");
01161
01162 context->request_id = parent_context->request_id;
01163 context->subrequest_id = ++(parent_context->subrequest_id);
01164 context->suppress_is_default = FALSE;
01165 context->convert2list = parent_context->convert2list;
01166 context->statusOverride = 0;
01167 context->is_subrequest = TRUE;
01168 context->userdata = NULL;
01169 context->last_modtime = 0;
01170 context->timeout = DEFAULT_TIMEOUT;
01171 context->user_modtime = 0;
01172 context->formdata=0;
01173 context->auth_info = parent_context->auth_info;
01174 context->retry = TRUE;
01175 context->method = METHOD_GET;
01176
01177
01178 context->selected_tags_tbl.table = NULL;
01179 context->suppressed_tags_tbl.table = NULL;
01180 context->stripped_tags_tbl.table = NULL;
01181
01182 context->type = parent_context->type;
01183 context->result_chunk = NULL;
01184
01185
01186 target = HTStreamToChunk(subrequest, &(context->result_chunk), 0);
01187 HTRequest_setOutputStream(subrequest, target);
01188
01189
01190 context->result_params =
01191 get_result_param_stub(&parent_context->result_params);
01192
01193
01194 context->request_result = result_term;
01195
01196 context->status_term = p2p_new();
01197
01198
01199 HTRequest_setContext(subrequest, (void *) context);
01200
01201
01202
01203
01204 #ifdef LIBWWW_DEBUG
01205 xsb_dbgmsg((LOG_DEBUG,"***Subrequest %s: context set", RequestID(subrequest)));
01206 #endif
01207
01208 return context;
01209
01210 }
01211
01212
01213
01214
01215
01216 void setup_termination_filter(HTRequest *request, HTNetAfter *filter)
01217 {
01218 HTRequest_addAfter(request,
01219 filter,
01220 NULL,
01221 NULL,
01222 HT_ALL,
01223 HT_FILTER_LAST,
01224 NO);
01225 }