1 /* $Id: url.c,v 1.95 2007/05/23 15:06:06 inu Exp $ */
3 #ifndef __MINGW32_VERSION
5 #include <sys/socket.h>
6 #include <netinet/in.h>
11 #endif /* __MINGW32_VERSION */
19 #include <io.h> /* ?? */
28 #ifndef SSLEAY_VERSION_NUMBER
29 #include <openssl/crypto.h> /* SSLEAY_VERSION_NUMBER may be here */
31 #include <openssl/err.h>
35 #define write(a,b,c) write_s(a,b,c)
36 #endif /* __WATT32__ */
38 #ifdef __MINGW32_VERSION
39 #define write(a,b,c) send(a,b,c, 0)
40 #define close(fd) closesocket(fd)
44 /* see rc.c, "dns_order" and dnsorders[] */
45 int ai_family_order_table[7][3] = {
46 {PF_UNSPEC, PF_UNSPEC, PF_UNSPEC}, /* 0:unspec */
47 {PF_INET, PF_INET6, PF_UNSPEC}, /* 1:inet inet6 */
48 {PF_INET6, PF_INET, PF_UNSPEC}, /* 2:inet6 inet */
49 {PF_UNSPEC, PF_UNSPEC, PF_UNSPEC}, /* 3: --- */
50 {PF_INET, PF_UNSPEC, PF_UNSPEC}, /* 4:inet */
51 {PF_UNSPEC, PF_UNSPEC, PF_UNSPEC}, /* 5: --- */
52 {PF_INET6, PF_UNSPEC, PF_UNSPEC}, /* 6:inet6 */
56 static JMP_BUF AbortLoading;
58 /* XXX: note html.h SCM_ */
65 0, /* local - not defined */
66 0, /* local-CGI - not defined? */
67 0, /* exec - not defined? */
72 0, /* data - not defined */
73 0, /* mailto - not defined */
79 struct cmdtable schemetable[] = {
81 {"gopher", SCM_GOPHER},
85 /* {"exec", SCM_EXEC}, */
87 /* {"nntp", SCM_NNTP_GROUP}, */
89 /* {"news", SCM_NEWS_GROUP}, */
92 {"mailto", SCM_MAILTO},
100 static struct table2 DefaultGuess[] = {
101 {"html", "text/html"},
102 {"htm", "text/html"},
103 {"shtml", "text/html"},
104 {"gif", "image/gif"},
105 {"jpeg", "image/jpeg"},
106 {"jpg", "image/jpeg"},
107 {"png", "image/png"},
108 {"xbm", "image/xbm"},
109 {"au", "audio/basic"},
110 {"gz", "application/x-gzip"},
111 {"Z", "application/x-compress"},
112 {"bz2", "application/x-bzip"},
113 {"tar", "application/x-tar"},
114 {"zip", "application/x-zip"},
115 {"lha", "application/x-lha"},
116 {"lzh", "application/x-lha"},
117 {"ps", "application/postscript"},
118 {"pdf", "application/pdf"},
122 static void add_index_file(ParsedURL *pu, URLFile *uf);
124 /* #define HTTP_DEFAULT_FILE "/index.html" */
126 #ifndef HTTP_DEFAULT_FILE
127 #define HTTP_DEFAULT_FILE "/"
128 #endif /* not HTTP_DEFAULT_FILE */
134 sock_log(char *message, ...)
136 FILE *f = fopen("zzzsocklog", "a");
141 va_start(va, message);
142 vfprintf(f, message, va);
148 static TextList *mimetypes_list;
149 static struct table2 **UserMimeTypes;
151 static struct table2 *
152 loadMimeTypes(char *filename)
158 struct table2 *mtypes;
160 f = fopen(expandPath(filename), "r");
164 while (tmp = Strfgets(f), tmp->length > 0) {
167 d = strtok(d, " \t\n\r");
169 d = strtok(NULL, " \t\n\r");
170 for (i = 0; d != NULL; i++)
171 d = strtok(NULL, " \t\n\r");
177 mtypes = New_N(struct table2, n + 1);
179 while (tmp = Strfgets(f), tmp->length > 0) {
183 type = strtok(d, " \t\n\r");
187 d = strtok(NULL, " \t\n\r");
190 mtypes[i].item1 = Strnew_charp(d)->ptr;
191 mtypes[i].item2 = Strnew_charp(type)->ptr;
195 mtypes[i].item1 = NULL;
196 mtypes[i].item2 = NULL;
207 if (non_null(mimetypes_files))
208 mimetypes_list = make_domain_list(mimetypes_files);
210 mimetypes_list = NULL;
211 if (mimetypes_list == NULL)
213 UserMimeTypes = New_N(struct table2 *, mimetypes_list->nitem);
214 for (i = 0, tl = mimetypes_list->first; tl; i++, tl = tl->next)
215 UserMimeTypes[i] = loadMimeTypes(tl->ptr);
219 DefaultFile(int scheme)
226 return allocStr(HTTP_DEFAULT_FILE, -1);
229 return allocStr("1", -1);
230 #endif /* USE_GOPHER */
235 return allocStr("/", -1);
240 static MySignalHandler
243 LONGJMP(AbortLoading, 1);
248 SSL_CTX *ssl_ctx = NULL;
254 SSL_CTX_free(ssl_ctx);
256 ssl_accept_this_site(NULL);
259 #if SSLEAY_VERSION_NUMBER >= 0x00905100
260 #include <openssl/rand.h>
269 if ((file = RAND_file_name(buffer, sizeof(buffer)))) {
271 if (RAND_egd(file) > 0)
274 RAND_load_file(file, -1);
278 srand48((long)time(NULL));
279 while (!RAND_status()) {
281 RAND_seed((unsigned char *)&l, sizeof(long));
285 RAND_write_file(file);
287 #endif /* SSLEAY_VERSION_NUMBER >= 0x00905100 */
290 openSSLHandle(int sock, char *hostname, char **p_cert)
293 static char *old_ssl_forbid_method = NULL;
294 #ifdef USE_SSL_VERIFY
295 static int old_ssl_verify_server = -1;
298 if (old_ssl_forbid_method != ssl_forbid_method
299 && (!old_ssl_forbid_method || !ssl_forbid_method ||
300 strcmp(old_ssl_forbid_method, ssl_forbid_method))) {
301 old_ssl_forbid_method = ssl_forbid_method;
302 #ifdef USE_SSL_VERIFY
303 ssl_path_modified = 1;
308 #ifdef USE_SSL_VERIFY
309 if (old_ssl_verify_server != ssl_verify_server) {
310 old_ssl_verify_server = ssl_verify_server;
311 ssl_path_modified = 1;
313 if (ssl_path_modified) {
315 ssl_path_modified = 0;
317 #endif /* defined(USE_SSL_VERIFY) */
318 if (ssl_ctx == NULL) {
320 #if SSLEAY_VERSION_NUMBER < 0x0800
321 ssl_ctx = SSL_CTX_new();
322 X509_set_default_verify_paths(ssl_ctx->cert);
323 #else /* SSLEAY_VERSION_NUMBER >= 0x0800 */
324 SSLeay_add_ssl_algorithms();
325 SSL_load_error_strings();
326 if (!(ssl_ctx = SSL_CTX_new(SSLv23_client_method())))
329 if (ssl_forbid_method) {
330 if (strchr(ssl_forbid_method, '2'))
331 option |= SSL_OP_NO_SSLv2;
332 if (strchr(ssl_forbid_method, '3'))
333 option |= SSL_OP_NO_SSLv3;
334 if (strchr(ssl_forbid_method, 't'))
335 option |= SSL_OP_NO_TLSv1;
336 if (strchr(ssl_forbid_method, 'T'))
337 option |= SSL_OP_NO_TLSv1;
339 SSL_CTX_set_options(ssl_ctx, option);
340 #ifdef USE_SSL_VERIFY
341 /* derived from openssl-0.9.5/apps/s_{client,cb}.c */
342 #if 1 /* use SSL_get_verify_result() to verify cert */
343 SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_NONE, NULL);
345 SSL_CTX_set_verify(ssl_ctx,
346 ssl_verify_server ? SSL_VERIFY_PEER :
347 SSL_VERIFY_NONE, NULL);
349 if (ssl_cert_file != NULL && *ssl_cert_file != '\0') {
351 if (SSL_CTX_use_certificate_file
352 (ssl_ctx, ssl_cert_file, SSL_FILETYPE_PEM) > 0) {
353 char *key_file = (ssl_key_file == NULL
355 '\0') ? ssl_cert_file : ssl_key_file;
356 if (SSL_CTX_use_PrivateKey_file
357 (ssl_ctx, key_file, SSL_FILETYPE_PEM) > 0)
358 if (SSL_CTX_check_private_key(ssl_ctx))
366 if ((!ssl_ca_file && !ssl_ca_path)
367 || SSL_CTX_load_verify_locations(ssl_ctx, ssl_ca_file, ssl_ca_path))
368 #endif /* defined(USE_SSL_VERIFY) */
369 SSL_CTX_set_default_verify_paths(ssl_ctx);
370 #endif /* SSLEAY_VERSION_NUMBER >= 0x0800 */
372 handle = SSL_new(ssl_ctx);
373 SSL_set_fd(handle, sock);
374 #if SSLEAY_VERSION_NUMBER >= 0x00905100
376 #endif /* SSLEAY_VERSION_NUMBER >= 0x00905100 */
377 if (SSL_connect(handle) > 0) {
378 Str serv_cert = ssl_get_certificate(handle, hostname);
380 *p_cert = serv_cert->ptr;
391 /* FIXME: gettextize? */
392 disp_err_message(Sprintf
394 ERR_error_string(ERR_get_error(), NULL))->ptr, FALSE);
399 SSL_write_from_file(SSL * ssl, char *file)
404 fd = fopen(file, "r");
406 while ((c = fgetc(fd)) != EOF) {
408 SSL_write(ssl, buf, 1);
417 write_from_file(int sock, char *file)
422 fd = fopen(file, "r");
424 while ((c = fgetc(fd)) != EOF) {
435 if (buf->bufferprop & BP_NO_URL) {
436 /* no URL is defined for the buffer */
439 if (buf->baseURL != NULL) {
440 /* <BASE> tag is defined in the document */
444 return &buf->currentURL;
448 openSocket(char *const hostname,
449 char *remoteport_name, unsigned short remoteport_num)
451 volatile int sock = -1;
454 struct addrinfo hints, *res0, *res;
457 #else /* not INET6 */
458 struct sockaddr_in hostaddr;
459 struct hostent *entry;
460 struct protoent *proto;
461 unsigned short s_port;
464 #endif /* not INET6 */
465 MySignalHandler(*volatile prevtrap) (SIGNAL_ARG) = NULL;
468 /* FIXME: gettextize? */
469 message(Sprintf("Opening socket...")->ptr, 0, 0);
472 if (SETJMP(AbortLoading) != 0) {
474 sock_log("openSocket() failed. reason: user abort\n");
481 if (hostname == NULL) {
483 sock_log("openSocket() failed. reason: Bad hostname \"%s\"\n",
490 /* rfc2732 compliance */
492 if (hname != NULL && hname[0] == '[' && hname[strlen(hname) - 1] == ']') {
493 hname = allocStr(hostname + 1, -1);
494 hname[strlen(hname) - 1] = '\0';
495 if (strspn(hname, "0123456789abcdefABCDEF:.") != strlen(hname))
498 for (af = ai_family_order_table[DNS_order];; af++) {
499 memset(&hints, 0, sizeof(hints));
500 hints.ai_family = *af;
501 hints.ai_socktype = SOCK_STREAM;
502 if (remoteport_num != 0) {
503 Str portbuf = Sprintf("%d", remoteport_num);
504 error = getaddrinfo(hname, portbuf->ptr, &hints, &res0);
509 if (error && remoteport_name && remoteport_name[0] != '\0') {
510 /* try default port */
511 error = getaddrinfo(hname, remoteport_name, &hints, &res0);
514 if (*af == PF_UNSPEC) {
517 /* try next ai family */
521 for (res = res0; res; res = res->ai_next) {
522 sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
526 if (connect(sock, res->ai_addr, res->ai_addrlen) < 0) {
535 if (*af == PF_UNSPEC) {
538 /* try next ai family */
544 #else /* not INET6 */
545 s_port = htons(remoteport_num);
546 bzero((char *)&hostaddr, sizeof(struct sockaddr_in));
547 if ((proto = getprotobyname("tcp")) == NULL) {
548 /* protocol number of TCP is 6 */
549 proto = New(struct protoent);
552 if ((sock = socket(AF_INET, SOCK_STREAM, proto->p_proto)) < 0) {
554 sock_log("openSocket: socket() failed. reason: %s\n", strerror(errno));
558 regexCompile("^[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+$", 0);
559 if (regexMatch(hostname, -1, 1)) {
560 sscanf(hostname, "%d.%d.%d.%d", &a1, &a2, &a3, &a4);
561 adr = htonl((a1 << 24) | (a2 << 16) | (a3 << 8) | a4);
562 bcopy((void *)&adr, (void *)&hostaddr.sin_addr, sizeof(long));
563 hostaddr.sin_family = AF_INET;
564 hostaddr.sin_port = s_port;
566 message(Sprintf("Connecting to %s", hostname)->ptr, 0, 0);
569 if (connect(sock, (struct sockaddr *)&hostaddr,
570 sizeof(struct sockaddr_in)) < 0) {
572 sock_log("openSocket: connect() failed. reason: %s\n",
582 message(Sprintf("Performing hostname lookup on %s", hostname)->ptr,
586 if ((entry = gethostbyname(hostname)) == NULL) {
588 sock_log("openSocket: gethostbyname() failed. reason: %s\n",
593 hostaddr.sin_family = AF_INET;
594 hostaddr.sin_port = s_port;
595 for (h_addr_list = entry->h_addr_list; *h_addr_list; h_addr_list++) {
596 bcopy((void *)h_addr_list[0], (void *)&hostaddr.sin_addr,
599 adr = ntohl(*(long *)&hostaddr.sin_addr);
600 sock_log("openSocket: connecting %d.%d.%d.%d\n",
602 (adr >> 16) & 0xff, (adr >> 8) & 0xff, adr & 0xff);
605 message(Sprintf("Connecting to %s", hostname)->ptr, 0, 0);
608 if ((result = connect(sock, (struct sockaddr *)&hostaddr,
609 sizeof(struct sockaddr_in))) == 0) {
614 sock_log("openSocket: connect() failed. reason: %s\n",
623 #endif /* not INET6 */
634 #define COPYPATH_SPC_ALLOW 0
635 #define COPYPATH_SPC_IGNORE 1
636 #define COPYPATH_SPC_REPLACE 2
639 copyPath(char *orgpath, int length, int option)
642 while (*orgpath && length != 0) {
643 if (IS_SPACE(*orgpath)) {
645 case COPYPATH_SPC_ALLOW:
646 Strcat_char(tmp, *orgpath);
648 case COPYPATH_SPC_IGNORE:
651 case COPYPATH_SPC_REPLACE:
652 Strcat_charp(tmp, "%20");
657 Strcat_char(tmp, *orgpath);
665 parseURL(char *url, ParsedURL *p_url, ParsedURL *current)
670 url = url_quote(url); /* quote 0x01-0x20, 0x7F-0xFF */
673 p_url->scheme = SCM_MISSING;
678 p_url->is_nocache = 0;
680 p_url->real_file = NULL;
684 /* RFC1808: Relative Uniform Resource Locators
685 * 4. Resolving Relative URLs
687 if (*url == '\0' || *url == '#') {
689 copyParsedURL(p_url, current);
692 #if defined( __EMX__ ) || defined( __CYGWIN__ )
693 if (!strncmp(url, "file://localhost/", 17)) {
694 p_url->scheme = SCM_LOCAL;
699 #ifdef SUPPORT_DOS_DRIVE_PREFIX
700 if (IS_ALPHA(*p) && (p[1] == ':' || p[1] == '|')) {
701 p_url->scheme = SCM_LOCAL;
704 #endif /* SUPPORT_DOS_DRIVE_PREFIX */
705 /* search for scheme */
706 p_url->scheme = getURLScheme(&p);
707 if (p_url->scheme == SCM_MISSING) {
708 /* scheme part is not found in the url. This means either
709 * (a) the url is relative to the current or (b) the url
710 * denotes a filename (therefore the scheme is SCM_LOCAL).
713 switch (current->scheme) {
716 p_url->scheme = SCM_LOCAL;
720 p_url->scheme = SCM_FTP;
725 p_url->scheme = SCM_NNTP;
729 p_url->scheme = SCM_NEWS;
733 p_url->scheme = current->scheme;
738 p_url->scheme = SCM_LOCAL;
740 if (!strncmp(p, "//", 2)) {
741 /* URL begins with // */
742 /* it means that 'scheme:' is abbreviated */
746 /* the url doesn't begin with '//' */
749 /* scheme part has been found */
750 if (p_url->scheme == SCM_UNKNOWN) {
751 p_url->file = allocStr(url, -1);
754 /* get host and port */
755 if (p[0] != '/' || p[1] != '/') { /* scheme:foo or scheme:/foo */
757 if (p_url->scheme != SCM_UNKNOWN)
758 p_url->port = DefaultPort[p_url->scheme];
763 /* after here, p begins with // */
764 if (p_url->scheme == SCM_LOCAL) { /* file://foo */
769 if (p[2] == '/' || p[2] == '~'
770 /* <A HREF="file:///foo">file:///foo</A> or <A HREF="file://~user">file://~user</A> */
771 #ifdef SUPPORT_DOS_DRIVE_PREFIX
772 || (IS_ALPHA(p[2]) && (p[3] == ':' || p[3] == '|'))
773 /* <A HREF="file://DRIVE/foo">file://DRIVE/foo</A> */
774 #endif /* SUPPORT_DOS_DRIVE_PREFIX */
781 p += 2; /* scheme://foo */
786 if (*q == '[') { /* rfc2732,rfc2373 compliance */
788 while (IS_XDIGIT(*p) || *p == ':' || *p == '.')
790 if (*p != ']' || (*(p + 1) && strchr(":/?#", *(p + 1)) == NULL))
794 while (*p && strchr(":/@?#", *p) == NULL)
798 /* scheme://user:pass@host or
801 p_url->host = copyPath(q, p - q, COPYPATH_SPC_IGNORE);
803 while (*p && strchr("@/?#", *p) == NULL)
806 /* scheme://user:pass@... */
807 p_url->pass = copyPath(q, p - q, COPYPATH_SPC_ALLOW);
809 p_url->user = p_url->host;
813 /* scheme://host:port/ */
814 tmp = Strnew_charp_n(q, p - q);
815 p_url->port = atoi(tmp->ptr);
816 /* *p is one of ['\0', '/', '?', '#'] */
819 /* scheme://user@... */
820 p_url->user = copyPath(q, p - q, COPYPATH_SPC_IGNORE);
828 p_url->host = copyPath(q, p - q, COPYPATH_SPC_IGNORE);
829 p_url->port = DefaultPort[p_url->scheme];
833 #ifndef SUPPORT_NETBIOS_SHARE
834 if (p_url->scheme == SCM_LOCAL && p_url->user == NULL &&
835 p_url->host != NULL && *p_url->host != '\0' &&
836 strcmp(p_url->host, "localhost")) {
838 * In the environments other than CYGWIN, a URL like
839 * file://host/file is regarded as ftp://host/file.
840 * On the other hand, file://host/file on CYGWIN is
841 * regarded as local access to the file //host/file.
842 * `host' is a netbios-hostname, drive, or any other
843 * name; It is CYGWIN system call who interprets that.
846 p_url->scheme = SCM_FTP; /* ftp://host/... */
847 if (p_url->port == 0)
848 p_url->port = DefaultPort[SCM_FTP];
851 if ((*p == '\0' || *p == '#' || *p == '?') && p_url->host == NULL) {
855 #ifdef SUPPORT_DOS_DRIVE_PREFIX
856 if (p_url->scheme == SCM_LOCAL) {
860 if (IS_ALPHA(q[0]) && (q[1] == ':' || q[1] == '|')) {
873 if (p_url->scheme == SCM_GOPHER) {
876 if (*q && q[0] != '/' && q[1] != '/' && q[2] == '/')
879 #endif /* USE_GOPHER */
882 if (*p == '\0' || *p == '#' || *p == '?') { /* scheme://host[:port]/ */
883 p_url->file = DefaultFile(p_url->scheme);
887 if (p_url->scheme == SCM_GOPHER && *p == 'R') {
890 Strcat_char(tmp, *(p++));
891 while (*p && *p != '/')
893 Strcat_charp(tmp, p);
896 p_url->file = copyPath(tmp->ptr, -1, COPYPATH_SPC_IGNORE);
899 #endif /* USE_GOPHER */
901 char *cgi = strchr(p, '?');
903 while (*p && *p != '#' && p != cgi)
905 if (*p == '#' && p_url->scheme == SCM_LOCAL) {
907 * According to RFC2396, # means the beginning of
908 * URI-reference, and # should be escaped. But,
909 * if the scheme is SCM_LOCAL, the special
910 * treatment will apply to # for convinience.
912 if (p > q && *(p - 1) == '/' && (cgi == NULL || p < cgi)) {
914 * # comes as the first character of the file name
915 * that means, # is not a label but a part of the file
921 else if (*(p + 1) == '\0') {
923 * # comes as the last character of the file name that
924 * means, # is not a label but a part of the file
930 if (p_url->scheme == SCM_LOCAL || p_url->scheme == SCM_MISSING)
931 p_url->file = copyPath(q, p - q, COPYPATH_SPC_ALLOW);
933 p_url->file = copyPath(q, p - q, COPYPATH_SPC_IGNORE);
939 while (*p && *p != '#')
941 p_url->query = copyPath(q, p - q, COPYPATH_SPC_ALLOW);
944 if (p_url->scheme == SCM_MISSING) {
945 p_url->scheme = SCM_LOCAL;
946 p_url->file = allocStr(p, -1);
950 p_url->label = allocStr(p + 1, -1);
955 #define initParsedURL(p) bzero(p,sizeof(ParsedURL))
956 #define ALLOC_STR(s) ((s)==NULL?NULL:allocStr(s,-1))
959 copyParsedURL(ParsedURL *p, ParsedURL *q)
961 p->scheme = q->scheme;
963 p->is_nocache = q->is_nocache;
964 p->user = ALLOC_STR(q->user);
965 p->pass = ALLOC_STR(q->pass);
966 p->host = ALLOC_STR(q->host);
967 p->file = ALLOC_STR(q->file);
968 p->real_file = ALLOC_STR(q->real_file);
969 p->label = ALLOC_STR(q->label);
970 p->query = ALLOC_STR(q->query);
974 parseURL2(char *url, ParsedURL *pu, ParsedURL *current)
978 int relative_uri = FALSE;
980 parseURL(url, pu, current);
981 #ifndef USE_W3MMAILER
982 if (pu->scheme == SCM_MAILTO)
985 if (pu->scheme == SCM_DATA)
987 if (pu->scheme == SCM_NEWS || pu->scheme == SCM_NEWS_GROUP) {
988 if (pu->file && !strchr(pu->file, '@') &&
989 (!(p = strchr(pu->file, '/')) || strchr(p + 1, '-') ||
991 pu->scheme = SCM_NEWS_GROUP;
993 pu->scheme = SCM_NEWS;
996 if (pu->scheme == SCM_NNTP || pu->scheme == SCM_NNTP_GROUP) {
997 if (pu->file && *pu->file == '/')
998 pu->file = allocStr(pu->file + 1, -1);
999 if (pu->file && !strchr(pu->file, '@') &&
1000 (!(p = strchr(pu->file, '/')) || strchr(p + 1, '-') ||
1002 pu->scheme = SCM_NNTP_GROUP;
1004 pu->scheme = SCM_NNTP;
1005 if (current && (current->scheme == SCM_NNTP ||
1006 current->scheme == SCM_NNTP_GROUP)) {
1007 if (pu->host == NULL) {
1008 pu->host = current->host;
1009 pu->port = current->port;
1014 if (pu->scheme == SCM_LOCAL) {
1015 char *q = expandName(file_unquote(pu->file));
1016 #ifdef SUPPORT_DOS_DRIVE_PREFIX
1018 if (IS_ALPHA(q[0]) && q[1] == ':') {
1019 drive = Strnew_charp_n(q, 2);
1020 Strcat_charp(drive, file_quote(q+2));
1021 pu->file = drive->ptr;
1025 pu->file = file_quote(q);
1028 if (current && (pu->scheme == current->scheme ||
1029 (pu->scheme == SCM_FTP && current->scheme == SCM_FTPDIR) ||
1030 (pu->scheme == SCM_LOCAL &&
1031 current->scheme == SCM_LOCAL_CGI))
1032 && pu->host == NULL) {
1033 /* Copy omitted element from the current URL */
1034 pu->user = current->user;
1035 pu->pass = current->pass;
1036 pu->host = current->host;
1037 pu->port = current->port;
1038 if (pu->file && *pu->file) {
1039 #ifdef USE_EXTERNAL_URI_LOADER
1040 if (pu->scheme == SCM_UNKNOWN
1041 && strchr(pu->file, ':') == NULL
1042 && current && (p = strchr(current->file, ':')) != NULL) {
1043 pu->file = Sprintf("%s:%s",
1044 allocStr(current->file,
1045 p - current->file), pu->file)->ptr;
1051 pu->scheme != SCM_GOPHER &&
1052 #endif /* USE_GOPHER */
1054 #ifdef SUPPORT_DOS_DRIVE_PREFIX
1055 && !(pu->scheme == SCM_LOCAL && IS_ALPHA(pu->file[0])
1056 && pu->file[1] == ':')
1059 /* file is relative [process 1] */
1061 if (current->file) {
1062 tmp = Strnew_charp(current->file);
1063 while (tmp->length > 0) {
1064 if (Strlastchar(tmp) == '/')
1068 Strcat_charp(tmp, p);
1069 pu->file = tmp->ptr;
1070 relative_uri = TRUE;
1074 else if (pu->scheme == SCM_GOPHER && pu->file[0] == '/') {
1076 pu->file = allocStr(p + 1, -1);
1078 #endif /* USE_GOPHER */
1080 else { /* scheme:[?query][#label] */
1081 pu->file = current->file;
1083 pu->query = current->query;
1085 /* comment: query part need not to be completed
1086 * from the current URL. */
1090 if (pu->scheme == SCM_LOCAL) {
1091 if (strncmp(pu->file, "/$LIB/", 6)) {
1092 char abs[_MAX_PATH];
1094 _abspath(abs, file_unquote(pu->file), _MAX_PATH);
1095 pu->file = file_quote(cleanupName(abs));
1099 if (pu->scheme == SCM_LOCAL && pu->file[0] != '/' &&
1100 #ifdef SUPPORT_DOS_DRIVE_PREFIX /* for 'drive:' */
1101 !(IS_ALPHA(pu->file[0]) && pu->file[1] == ':') &&
1103 strcmp(pu->file, "-")) {
1104 /* local file, relative path */
1105 tmp = Strnew_charp(CurrentDir);
1106 if (Strlastchar(tmp) != '/')
1107 Strcat_char(tmp, '/');
1108 Strcat_charp(tmp, file_unquote(pu->file));
1109 pu->file = file_quote(cleanupName(tmp->ptr));
1112 else if (pu->scheme == SCM_HTTP
1114 || pu->scheme == SCM_HTTPS
1118 /* In this case, pu->file is created by [process 1] above.
1119 * pu->file may contain relative path (for example,
1120 * "/foo/../bar/./baz.html"), cleanupName() must be applied.
1121 * When the entire abs_path is given, it still may contain
1122 * elements like `//', `..' or `.' in the pu->file. It is
1123 * server's responsibility to canonicalize such path.
1125 pu->file = cleanupName(pu->file);
1130 pu->scheme != SCM_GOPHER &&
1131 #endif /* USE_GOPHER */
1132 pu->file[0] == '/') {
1134 * this happens on the following conditions:
1135 * (1) ftp scheme (2) local, looks like absolute path.
1136 * In both case, there must be no side effect with
1137 * cleanupName(). (I hope so...)
1139 pu->file = cleanupName(pu->file);
1141 if (pu->scheme == SCM_LOCAL) {
1142 #ifdef SUPPORT_NETBIOS_SHARE
1143 if (pu->host && strcmp(pu->host, "localhost") != 0) {
1144 Str tmp = Strnew_charp("//");
1145 Strcat_m_charp(tmp, pu->host,
1146 cleanupName(file_unquote(pu->file)), NULL);
1147 pu->real_file = tmp->ptr;
1151 pu->real_file = cleanupName(file_unquote(pu->file));
1157 _parsedURL2Str(ParsedURL *pu, int pass)
1160 static char *scheme_str[] = {
1161 "http", "gopher", "ftp", "ftp", "file", "file", "exec", "nntp", "nntp",
1162 "news", "news", "data", "mailto",
1165 #endif /* USE_SSL */
1168 if (pu->scheme == SCM_MISSING) {
1169 return Strnew_charp("???");
1171 else if (pu->scheme == SCM_UNKNOWN) {
1172 return Strnew_charp(pu->file);
1174 if (pu->host == NULL && pu->file == NULL && pu->label != NULL) {
1176 return Sprintf("#%s", pu->label);
1178 if (pu->scheme == SCM_LOCAL && !strcmp(pu->file, "-")) {
1179 tmp = Strnew_charp("-");
1181 Strcat_char(tmp, '#');
1182 Strcat_charp(tmp, pu->label);
1186 tmp = Strnew_charp(scheme_str[pu->scheme]);
1187 Strcat_char(tmp, ':');
1188 #ifndef USE_W3MMAILER
1189 if (pu->scheme == SCM_MAILTO) {
1190 Strcat_charp(tmp, pu->file);
1192 Strcat_char(tmp, '?');
1193 Strcat_charp(tmp, pu->query);
1198 if (pu->scheme == SCM_DATA) {
1199 Strcat_charp(tmp, pu->file);
1203 if (pu->scheme != SCM_NEWS && pu->scheme != SCM_NEWS_GROUP)
1204 #endif /* USE_NNTP */
1206 Strcat_charp(tmp, "//");
1209 Strcat_charp(tmp, pu->user);
1210 if (pass && pu->pass) {
1211 Strcat_char(tmp, ':');
1212 Strcat_charp(tmp, pu->pass);
1214 Strcat_char(tmp, '@');
1217 Strcat_charp(tmp, pu->host);
1218 if (pu->port != DefaultPort[pu->scheme]) {
1219 Strcat_char(tmp, ':');
1220 Strcat(tmp, Sprintf("%d", pu->port));
1225 pu->scheme != SCM_NEWS && pu->scheme != SCM_NEWS_GROUP &&
1226 #endif /* USE_NNTP */
1227 (pu->file == NULL || (pu->file[0] != '/'
1228 #ifdef SUPPORT_DOS_DRIVE_PREFIX
1229 && !(IS_ALPHA(pu->file[0])
1230 && pu->file[1] == ':'
1231 && pu->host == NULL)
1234 Strcat_char(tmp, '/');
1235 Strcat_charp(tmp, pu->file);
1236 if (pu->scheme == SCM_FTPDIR && Strlastchar(tmp) != '/')
1237 Strcat_char(tmp, '/');
1239 Strcat_char(tmp, '?');
1240 Strcat_charp(tmp, pu->query);
1243 Strcat_char(tmp, '#');
1244 Strcat_charp(tmp, pu->label);
1250 parsedURL2Str(ParsedURL *pu)
1252 return _parsedURL2Str(pu, FALSE);
1256 getURLScheme(char **url)
1260 int scheme = SCM_MISSING;
1262 while (*p && (IS_ALNUM(*p) || *p == '.' || *p == '+' || *p == '-'))
1264 if (*p == ':') { /* scheme found */
1265 scheme = SCM_UNKNOWN;
1266 for (i = 0; (q = schemetable[i].cmdname) != NULL; i++) {
1267 int len = strlen(q);
1268 if (!strncasecmp(q, *url, len) && (*url)[len] == ':') {
1269 scheme = schemetable[i].cmd;
1279 otherinfo(ParsedURL *target, ParsedURL *current, char *referer)
1283 Strcat_charp(s, "User-Agent: ");
1284 if (UserAgent == NULL || *UserAgent == '\0')
1285 Strcat_charp(s, w3m_version);
1287 Strcat_charp(s, UserAgent);
1288 Strcat_charp(s, "\r\n");
1290 Strcat_m_charp(s, "Accept: ", AcceptMedia, "\r\n", NULL);
1291 Strcat_m_charp(s, "Accept-Encoding: ", AcceptEncoding, "\r\n", NULL);
1292 Strcat_m_charp(s, "Accept-Language: ", AcceptLang, "\r\n", NULL);
1295 Strcat_charp(s, "Host: ");
1296 Strcat_charp(s, target->host);
1297 if (target->port != DefaultPort[target->scheme])
1298 Strcat(s, Sprintf(":%d", target->port));
1299 Strcat_charp(s, "\r\n");
1301 if (target->is_nocache || NoCache) {
1302 Strcat_charp(s, "Pragma: no-cache\r\n");
1303 Strcat_charp(s, "Cache-control: no-cache\r\n");
1305 if (!NoSendReferer) {
1306 if (referer == NULL && current && current->scheme != SCM_LOCAL &&
1307 (current->scheme != SCM_FTP ||
1308 (current->user == NULL && current->pass == NULL))) {
1309 char *p = current->label;
1310 Strcat_charp(s, "Referer: ");
1311 current->label = NULL;
1312 Strcat(s, parsedURL2Str(current));
1314 Strcat_charp(s, "\r\n");
1316 else if (referer != NULL && referer != NO_REFERER) {
1317 char *p = strchr(referer, '#');
1318 Strcat_charp(s, "Referer: ");
1320 Strcat_charp_n(s, referer, p - referer);
1322 Strcat_charp(s, referer);
1323 Strcat_charp(s, "\r\n");
1330 HTTPrequestMethod(HRequest *hr)
1332 switch (hr->command) {
1333 case HR_COMMAND_CONNECT:
1334 return Strnew_charp("CONNECT");
1335 case HR_COMMAND_POST:
1336 return Strnew_charp("POST");
1338 case HR_COMMAND_HEAD:
1339 return Strnew_charp("HEAD");
1341 case HR_COMMAND_GET:
1343 return Strnew_charp("GET");
1349 HTTPrequestURI(ParsedURL *pu, HRequest *hr)
1352 if (hr->command == HR_COMMAND_CONNECT) {
1353 Strcat_charp(tmp, pu->host);
1354 Strcat(tmp, Sprintf(":%d", pu->port));
1356 else if (hr->flag & HR_FLAG_LOCAL) {
1357 Strcat_charp(tmp, pu->file);
1359 Strcat_char(tmp, '?');
1360 Strcat_charp(tmp, pu->query);
1364 char *save_label = pu->label;
1366 Strcat(tmp, _parsedURL2Str(pu, TRUE));
1367 pu->label = save_label;
1373 HTTPrequest(ParsedURL *pu, ParsedURL *current, HRequest *hr, TextList *extra)
1377 int seen_www_auth = 0;
1378 int seen_proxy_auth = 0;
1381 #endif /* USE_COOKIE */
1382 tmp = HTTPrequestMethod(hr);
1383 Strcat_charp(tmp, " ");
1384 Strcat_charp(tmp, HTTPrequestURI(pu, hr)->ptr);
1385 Strcat_charp(tmp, " HTTP/1.0\r\n");
1386 if (hr->referer == NO_REFERER)
1387 Strcat_charp(tmp, otherinfo(pu, NULL, NULL));
1389 Strcat_charp(tmp, otherinfo(pu, current, hr->referer));
1391 for (i = extra->first; i != NULL; i = i->next) {
1392 if (strncasecmp(i->ptr, "Authorization:",
1393 sizeof("Authorization:") - 1) == 0) {
1396 if (hr->command == HR_COMMAND_CONNECT)
1400 if (strncasecmp(i->ptr, "Proxy-Authorization:",
1401 sizeof("Proxy-Authorization:") - 1) == 0) {
1402 seen_proxy_auth = 1;
1404 if (pu->scheme == SCM_HTTPS
1405 && hr->command != HR_COMMAND_CONNECT)
1409 Strcat_charp(tmp, i->ptr);
1413 if (hr->command != HR_COMMAND_CONNECT &&
1414 use_cookie && (cookie = find_cookie(pu))) {
1415 Strcat_charp(tmp, "Cookie: ");
1416 Strcat(tmp, cookie);
1417 Strcat_charp(tmp, "\r\n");
1418 /* [DRAFT 12] s. 10.1 */
1419 if (cookie->ptr[0] != '$')
1420 Strcat_charp(tmp, "Cookie2: $Version=\"1\"\r\n");
1422 #endif /* USE_COOKIE */
1423 if (hr->command == HR_COMMAND_POST) {
1424 if (hr->request->enctype == FORM_ENCTYPE_MULTIPART) {
1425 Strcat_charp(tmp, "Content-type: multipart/form-data; boundary=");
1426 Strcat_charp(tmp, hr->request->boundary);
1427 Strcat_charp(tmp, "\r\n");
1429 Sprintf("Content-length: %ld\r\n", hr->request->length));
1430 Strcat_charp(tmp, "\r\n");
1433 if (!override_content_type) {
1435 "Content-type: application/x-www-form-urlencoded\r\n");
1438 Sprintf("Content-length: %ld\r\n", hr->request->length));
1440 Strcat(tmp, header_string);
1441 Strcat_charp(tmp, "\r\n");
1442 Strcat_charp_n(tmp, hr->request->body, hr->request->length);
1443 Strcat_charp(tmp, "\r\n");
1448 Strcat(tmp, header_string);
1449 Strcat_charp(tmp, "\r\n");
1452 fprintf(stderr, "HTTPrequest: [ %s ]\n\n", tmp->ptr);
1458 init_stream(URLFile *uf, int scheme, InputStream stream)
1460 memset(uf, 0, sizeof(URLFile));
1461 uf->stream = stream;
1462 uf->scheme = scheme;
1463 uf->encoding = ENC_7BIT;
1465 uf->compression = CMP_NOCOMPRESS;
1466 uf->content_encoding = CMP_NOCOMPRESS;
1467 uf->guess_type = NULL;
1473 openURL(char *url, ParsedURL *pu, ParsedURL *current,
1474 URLOption *option, FormList *request, TextList *extra_header,
1475 URLFile *ouf, HRequest *hr, unsigned char *status)
1484 #endif /* USE_SSL */
1493 init_stream(&uf, SCM_MISSING, NULL);
1497 scheme = getURLScheme(&u);
1498 if (current == NULL && scheme == SCM_MISSING && !ArgvIsURL)
1499 u = file_to_url(url); /* force to local file */
1503 parseURL2(u, pu, current);
1504 if (pu->scheme == SCM_LOCAL && pu->file == NULL) {
1505 if (pu->label != NULL) {
1506 /* #hogege is not a label but a filename */
1507 Str tmp2 = Strnew_charp("#");
1508 Strcat_charp(tmp2, pu->label);
1509 pu->file = tmp2->ptr;
1510 pu->real_file = cleanupName(file_unquote(pu->file));
1514 /* given URL must be null string */
1516 sock_log("given URL must be null string\n");
1522 uf.scheme = pu->scheme;
1523 uf.url = parsedURL2Str(pu)->ptr;
1524 pu->is_nocache = (option->flag & RG_NOCACHE);
1525 uf.ext = filename_extension(pu->file, 1);
1527 hr->command = HR_COMMAND_GET;
1529 hr->referer = option->referer;
1530 hr->request = request;
1532 switch (pu->scheme) {
1535 if (request && request->body)
1536 /* local CGI: POST */
1537 uf.stream = newFileStream(localcgi_post(pu->real_file, pu->query,
1538 request, option->referer),
1539 (void (*)())fclose);
1541 /* lodal CGI: GET */
1542 uf.stream = newFileStream(localcgi_get(pu->real_file, pu->query,
1544 (void (*)())fclose);
1547 uf.scheme = pu->scheme = SCM_LOCAL_CGI;
1550 examineFile(pu->real_file, &uf);
1551 if (uf.stream == NULL) {
1552 if (dir_exist(pu->real_file)) {
1553 add_index_file(pu, &uf);
1554 if (uf.stream == NULL)
1557 else if (document_root != NULL) {
1558 tmp = Strnew_charp(document_root);
1559 if (Strlastchar(tmp) != '/' && pu->file[0] != '/')
1560 Strcat_char(tmp, '/');
1561 Strcat_charp(tmp, pu->file);
1562 p = cleanupName(tmp->ptr);
1563 q = cleanupName(file_unquote(p));
1567 add_index_file(pu, &uf);
1568 if (uf.stream == NULL) {
1573 examineFile(q, &uf);
1581 if (uf.stream == NULL && retryAsHttp && url[0] != '/') {
1582 if (scheme == SCM_MISSING || scheme == SCM_UNKNOWN) {
1583 /* retry it as "http://" */
1584 u = Strnew_m_charp("http://", url, NULL)->ptr;
1591 if (pu->file == NULL)
1592 pu->file = allocStr("/", -1);
1593 if (non_null(FTP_proxy) &&
1594 !Do_not_use_proxy &&
1595 pu->host != NULL && !check_no_proxy(pu->host)) {
1596 hr->flag |= HR_FLAG_PROXY;
1597 sock = openSocket(FTP_proxy_parsed.host,
1598 schemetable[FTP_proxy_parsed.scheme].cmdname,
1599 FTP_proxy_parsed.port);
1602 uf.scheme = SCM_HTTP;
1603 tmp = HTTPrequest(pu, current, hr, extra_header);
1604 write(sock, tmp->ptr, tmp->length);
1607 uf.stream = openFTPStream(pu, &uf);
1608 uf.scheme = pu->scheme;
1615 #endif /* USE_SSL */
1616 if (pu->file == NULL)
1617 pu->file = allocStr("/", -1);
1618 if (request && request->method == FORM_METHOD_POST && request->body)
1619 hr->command = HR_COMMAND_POST;
1620 if (request && request->method == FORM_METHOD_HEAD)
1621 hr->command = HR_COMMAND_HEAD;
1624 (pu->scheme == SCM_HTTPS) ? non_null(HTTPS_proxy) :
1625 #endif /* USE_SSL */
1626 non_null(HTTP_proxy)) && !Do_not_use_proxy &&
1627 pu->host != NULL && !check_no_proxy(pu->host)) {
1628 hr->flag |= HR_FLAG_PROXY;
1630 if (pu->scheme == SCM_HTTPS && *status == HTST_CONNECT) {
1631 sock = ssl_socket_of(ouf->stream);
1632 if (!(sslh = openSSLHandle(sock, pu->host,
1633 &uf.ssl_certificate))) {
1634 *status = HTST_MISSING;
1638 else if (pu->scheme == SCM_HTTPS) {
1639 sock = openSocket(HTTPS_proxy_parsed.host,
1640 schemetable[HTTPS_proxy_parsed.scheme].
1641 cmdname, HTTPS_proxy_parsed.port);
1645 #endif /* USE_SSL */
1646 sock = openSocket(HTTP_proxy_parsed.host,
1647 schemetable[HTTP_proxy_parsed.scheme].
1648 cmdname, HTTP_proxy_parsed.port);
1652 #endif /* USE_SSL */
1655 sock_log("Can't open socket\n");
1660 if (pu->scheme == SCM_HTTPS) {
1661 if (*status == HTST_NORMAL) {
1662 hr->command = HR_COMMAND_CONNECT;
1663 tmp = HTTPrequest(pu, current, hr, extra_header);
1664 *status = HTST_CONNECT;
1667 hr->flag |= HR_FLAG_LOCAL;
1668 tmp = HTTPrequest(pu, current, hr, extra_header);
1669 *status = HTST_NORMAL;
1673 #endif /* USE_SSL */
1675 tmp = HTTPrequest(pu, current, hr, extra_header);
1676 *status = HTST_NORMAL;
1680 sock = openSocket(pu->host,
1681 schemetable[pu->scheme].cmdname, pu->port);
1683 *status = HTST_MISSING;
1687 if (pu->scheme == SCM_HTTPS) {
1688 if (!(sslh = openSSLHandle(sock, pu->host,
1689 &uf.ssl_certificate))) {
1690 *status = HTST_MISSING;
1694 #endif /* USE_SSL */
1695 hr->flag |= HR_FLAG_LOCAL;
1696 tmp = HTTPrequest(pu, current, hr, extra_header);
1697 *status = HTST_NORMAL;
1700 if (pu->scheme == SCM_HTTPS) {
1701 uf.stream = newSSLStream(sslh, sock);
1703 SSL_write(sslh, tmp->ptr, tmp->length);
1705 write(sock, tmp->ptr, tmp->length);
1707 FILE *ff = fopen(w3m_reqlog, "a");
1709 fputs("HTTPS: request via SSL\n", ff);
1711 fputs("HTTPS: request without SSL\n", ff);
1712 fwrite(tmp->ptr, sizeof(char), tmp->length, ff);
1715 if (hr->command == HR_COMMAND_POST &&
1716 request->enctype == FORM_ENCTYPE_MULTIPART) {
1718 SSL_write_from_file(sslh, request->body);
1720 write_from_file(sock, request->body);
1725 #endif /* USE_SSL */
1727 write(sock, tmp->ptr, tmp->length);
1729 FILE *ff = fopen(w3m_reqlog, "a");
1730 fwrite(tmp->ptr, sizeof(char), tmp->length, ff);
1733 if (hr->command == HR_COMMAND_POST &&
1734 request->enctype == FORM_ENCTYPE_MULTIPART)
1735 write_from_file(sock, request->body);
1740 if (non_null(GOPHER_proxy) &&
1741 !Do_not_use_proxy &&
1742 pu->host != NULL && !check_no_proxy(pu->host)) {
1743 hr->flag |= HR_FLAG_PROXY;
1744 sock = openSocket(GOPHER_proxy_parsed.host,
1745 schemetable[GOPHER_proxy_parsed.scheme].cmdname,
1746 GOPHER_proxy_parsed.port);
1749 uf.scheme = SCM_HTTP;
1750 tmp = HTTPrequest(pu, current, hr, extra_header);
1753 sock = openSocket(pu->host,
1754 schemetable[pu->scheme].cmdname, pu->port);
1757 if (pu->file == NULL)
1759 tmp = Strnew_charp(file_unquote(pu->file));
1760 Strcat_char(tmp, '\n');
1762 write(sock, tmp->ptr, tmp->length);
1764 #endif /* USE_GOPHER */
1767 case SCM_NNTP_GROUP:
1769 case SCM_NEWS_GROUP:
1770 if (pu->scheme == SCM_NNTP || pu->scheme == SCM_NEWS)
1771 uf.scheme = SCM_NEWS;
1773 uf.scheme = SCM_NEWS_GROUP;
1774 uf.stream = openNewsStream(pu);
1776 #endif /* USE_NNTP */
1778 if (pu->file == NULL)
1780 p = Strnew_charp(pu->file)->ptr;
1785 tmp = Strnew_charp(q);
1786 q = strrchr(p, ';');
1787 if (q != NULL && !strcmp(q, ";base64")) {
1789 uf.encoding = ENC_BASE64;
1792 tmp = Str_url_unquote(tmp, FALSE, FALSE);
1793 uf.stream = newStrStream(tmp);
1794 uf.guess_type = (*p != '\0') ? p : "text/plain";
1800 uf.stream = newInputStream(sock);
1804 /* add index_file if exists */
1806 add_index_file(ParsedURL *pu, URLFile *uf)
1810 if (index_file == NULL || index_file[0] == '\0') {
1814 p = Strnew_m_charp(pu->file, "/", file_quote(index_file), NULL)->ptr;
1816 q = cleanupName(file_unquote(p));
1818 if (uf->stream == NULL)
1826 guessContentTypeFromTable(struct table2 *table, char *filename)
1832 p = &filename[strlen(filename) - 1];
1833 while (filename < p && *p != '.')
1838 for (t = table; t->item1; t++) {
1839 if (!strcmp(p, t->item1))
1842 for (t = table; t->item1; t++) {
1843 if (!strcasecmp(p, t->item1))
1850 guessContentType(char *filename)
1855 if (filename == NULL)
1857 if (mimetypes_list == NULL)
1858 goto no_user_mimetypes;
1860 for (i = 0; i < mimetypes_list->nitem; i++) {
1862 guessContentTypeFromTable(UserMimeTypes[i], filename)) != NULL)
1867 return guessContentTypeFromTable(DefaultGuess, filename);
1871 make_domain_list(char *domain_list)
1875 TextList *domains = NULL;
1878 tmp = Strnew_size(64);
1880 while (*p && IS_SPACE(*p))
1883 while (*p && !IS_SPACE(*p) && *p != ',')
1884 Strcat_char(tmp, *p++);
1885 if (tmp->length > 0) {
1886 if (domains == NULL)
1887 domains = newTextList();
1888 pushText(domains, tmp->ptr);
1890 while (*p && IS_SPACE(*p))
1899 domain_match(char *pat, char *domain)
1906 if (!strcasecmp(pat, domain))
1908 domain = strchr(domain, '.');
1916 check_no_proxy(char *domain)
1919 volatile int ret = 0;
1920 MySignalHandler(*volatile prevtrap) (SIGNAL_ARG) = NULL;
1922 if (NO_proxy_domains == NULL || NO_proxy_domains->nitem == 0 ||
1925 for (tl = NO_proxy_domains->first; tl != NULL; tl = tl->next) {
1926 if (domain_match(tl->ptr, domain))
1929 if (!NOproxy_netaddr) {
1933 * to check noproxy by network addr
1935 if (SETJMP(AbortLoading) != 0) {
1944 unsigned char **h_addr_list;
1945 char addr[4 * 16], buf[5];
1947 he = gethostbyname(domain);
1952 for (h_addr_list = (unsigned char **)he->h_addr_list; *h_addr_list;
1954 sprintf(addr, "%d", h_addr_list[0][0]);
1955 for (n = 1; n < he->h_length; n++) {
1956 sprintf(buf, ".%d", h_addr_list[0][n]);
1959 for (tl = NO_proxy_domains->first; tl != NULL; tl = tl->next) {
1960 if (strncmp(tl->ptr, addr, strlen(tl->ptr)) == 0) {
1968 struct addrinfo hints;
1969 struct addrinfo *res, *res0;
1973 for (af = ai_family_order_table[DNS_order];; af++) {
1974 memset(&hints, 0, sizeof(hints));
1975 hints.ai_family = *af;
1976 error = getaddrinfo(domain, NULL, &hints, &res0);
1978 if (*af == PF_UNSPEC) {
1984 for (res = res0; res != NULL; res = res->ai_next) {
1985 switch (res->ai_family) {
1988 &((struct sockaddr_in *)res->ai_addr)->sin_addr,
1989 addr, sizeof(addr));
1993 &((struct sockaddr_in6 *)res->ai_addr)->
1994 sin6_addr, addr, sizeof(addr));
2000 for (tl = NO_proxy_domains->first; tl != NULL; tl = tl->next) {
2001 if (strncmp(tl->ptr, addr, strlen(tl->ptr)) == 0) {
2009 if (*af == PF_UNSPEC) {
2021 filename_extension(char *path, int is_url)
2023 char *last_dot = "", *p = path;
2034 else if (is_url && *p == '?')
2037 if (*last_dot == '.') {
2038 for (i = 1; last_dot[i] && i < 8; i++) {
2039 if (is_url && !IS_ALNUM(last_dot[i]))
2042 return allocStr(last_dot, i);
2048 #ifdef USE_EXTERNAL_URI_LOADER
2049 static struct table2 **urimethods;
2050 static struct table2 default_urimethods[] = {
2051 {"mailto", "file:///$LIB/w3mmail.cgi?%s"},
2055 static struct table2 *
2056 loadURIMethods(char *filename)
2064 f = fopen(expandPath(filename), "r");
2068 while (tmp = Strfgets(f), tmp->length > 0) {
2069 if (tmp->ptr[0] != '#')
2074 um = New_N(struct table2, n + 1);
2076 while (tmp = Strfgets(f), tmp->length > 0) {
2077 if (tmp->ptr[0] == '#')
2079 while (IS_SPACE(Strlastchar(tmp)))
2081 for (up = p = tmp->ptr; *p != '\0'; p++) {
2083 um[i].item1 = Strnew_charp_n(up, p - up)->ptr;
2090 while (*p != '\0' && IS_SPACE(*p))
2092 um[i].item2 = Strnew_charp(p)->ptr;
2104 TextList *methodmap_list = NULL;
2108 if (non_null(urimethodmap_files))
2109 methodmap_list = make_domain_list(urimethodmap_files);
2110 if (methodmap_list == NULL)
2112 urimethods = New_N(struct table2 *, (methodmap_list->nitem + 1));
2113 for (i = 0, tl = methodmap_list->first; tl; tl = tl->next) {
2114 urimethods[i] = loadURIMethods(tl->ptr);
2118 urimethods[i] = NULL;
2122 searchURIMethods(ParsedURL *pu)
2130 if (pu->scheme != SCM_UNKNOWN)
2131 return NULL; /* use internal */
2132 if (urimethods == NULL)
2134 url = parsedURL2Str(pu);
2135 for (p = url->ptr; *p != '\0'; p++) {
2137 scheme = Strnew_charp_n(url->ptr, p - url->ptr);
2145 * RFC2396 3.1. Scheme Component
2146 * For resiliency, programs interpreting URI should treat upper case
2147 * letters as equivalent to lower case in scheme names (e.g., allow
2148 * "HTTP" as well as "http").
2150 for (i = 0; (ump = urimethods[i]) != NULL; i++) {
2151 for (; ump->item1 != NULL; ump++) {
2152 if (strcasecmp(ump->item1, scheme->ptr) == 0) {
2153 return Sprintf(ump->item2, url_quote(url->ptr));
2157 for (ump = default_urimethods; ump->item1 != NULL; ump++) {
2158 if (strcasecmp(ump->item1, scheme->ptr) == 0) {
2159 return Sprintf(ump->item2, url_quote(url->ptr));
2166 * RFC2396: Uniform Resource Identifiers (URI): Generic Syntax
2167 * Appendix A. Collected BNF for URI
2168 * uric = reserved | unreserved | escaped
2169 * reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" |
2171 * unreserved = alphanum | mark
2172 * mark = "-" | "_" | "." | "!" | "~" | "*" | "'" |
2174 * escaped = "%" hex hex
2177 #define URI_PATTERN "([-;/?:@&=+$,a-zA-Z0-9_.!~*'()]|%[0-9A-Fa-f][0-9A-Fa-f])*"
2179 chkExternalURIBuffer(Buffer *buf)
2184 for (i = 0; (ump = urimethods[i]) != NULL; i++) {
2185 for (; ump->item1 != NULL; ump++) {
2186 reAnchor(buf, Sprintf("%s:%s", ump->item1, URI_PATTERN)->ptr);
2189 for (ump = default_urimethods; ump->item1 != NULL; ump++) {
2190 reAnchor(buf, Sprintf("%s:%s", ump->item1, URI_PATTERN)->ptr);
2196 schemeToProxy(int scheme)
2198 ParsedURL *pu = NULL; /* for gcc */
2201 pu = &HTTP_proxy_parsed;
2205 pu = &HTTPS_proxy_parsed;
2209 pu = &FTP_proxy_parsed;
2213 pu = &GOPHER_proxy_parsed;