18 #include "lt-memory.h"
19 #include "lt-errmsg.h"
20 #include "lt-comment.h"
24 #define Strerror() strErr()
26 #define Realloc srealloc
28 #define fopen stdsfopen
34 #define LT_ERROR(err, format) fprintf(stderr, format)
35 #define LT_ERROR1(err, format, arg) fprintf(stderr, format, arg)
36 #define LT_ERROR2(err, format, arg1, arg2) fprintf(stderr, format, arg1, arg2)
37 #define LT_ERROR3(err, format, arg1, arg2, arg3) fprintf(stderr, format, arg1, arg2, arg3)
38 #define WARN(err, format) fprintf(stderr, format)
39 #define WARN1(err, format, arg) fprintf(stderr, format, arg)
41 #define Strerror() strerror(errno)
44 #define CWDBS MAXPATHLEN+1
49 #define GETWD(buf) getcwd(buf,CWDBS)
59 #include <sys/types.h>
65 #ifdef SOCKETS_IMPLEMENTED
74 #include <sys/socket.h>
75 #include <netinet/in.h>
92 static FILE16 *http_open(
const char *url,
93 const char *host,
int port,
const char *path,
95 static FILE16 *file_open(
const char *url,
96 const char *host,
int port,
const char *path,
99 static void parse_url(
const char *url,
100 char **scheme,
char **host,
int *port,
char **path);
106 FILE16 *(*open)(
const char *,
const char *, int,
const char *,
const char *);
108 {(
char *)
"http", http_open},
109 {(
char *)
"file", file_open},
111 #define NSCHEME (sizeof(schemes) / sizeof(schemes[0]))
115 char *default_base_url(
void)
122 WARN(LEFILE,
"Warning: can't get current directory for default base url\n");
123 return strdup8(
"file:/");
137 url = Malloc(6 + strlen(buf) + 2);
138 sprintf(url,
"file:/%s/", buf);
154 url = Malloc(6 + strlen(buf) + 2);
155 sprintf(url,
"file:/%s/", buf);
161 url = Malloc(5 + strlen(buf) + 2);
162 sprintf(url,
"file:%s/", buf);
178 char *url_merge(
const char *url,
const char *base,
179 char **_scheme,
char **_host,
int *_port,
char **_path)
181 char *merged_scheme, *merged_host, *merged_path, *merged_url;
182 char *scheme=0, *host=0, *path=0;
183 char *base_scheme=0, *base_host=0, *base_path=0;
184 char *default_base=0;
185 int port, base_port, merged_port, i, j;
190 parse_url(url, &scheme, &host, &port, &path);
191 if(scheme && (host || *path ==
'/'))
193 merged_scheme = scheme;
197 merged_url = strdup8(url);
204 base = default_base = default_base_url();
206 parse_url(base, &base_scheme, &base_host, &base_port, &base_path);
207 if(base_scheme && (base_host || *base_path ==
'/'))
211 LT_ERROR1(LEFILE,
"Error: bad base URL <%s>\n", base);
227 merged_path = Malloc(strlen(base_path) + strlen(path) + 1);
228 strcpy(merged_path, base_path);
232 for(i=strlen(merged_path)-1; i>=0 && merged_path[i] !=
'/'; i--)
233 merged_path[i] =
'\0';
237 strcat(merged_path, path);
248 for(j=i+1; p[j] && p[j] !=
'/'; j++)
253 if(j - i == 2 && p[i+1] ==
'.')
255 strcpy(&p[i+1], p[j] ? &p[j+1] : &p[j]);
265 if(p[j] ==
'/' && p[j+1] ==
'.' && p[j+2] ==
'.' &&
266 (p[j+3] ==
'/' || p[j+3] ==
'\0') &&
267 (j - i != 3 || p[i+1] !=
'.' || p[i+2] !=
'.'))
269 strcpy(&p[i+1], p[j+3] ? &p[j+4] : &p[j+3]);
282 if(scheme && !host && *path !=
'/')
284 if(strcmp(scheme, base_scheme) == 0)
287 "Warning: relative URL <%s> contains scheme, contrary to RFC 1808\n",
293 "Error: relative URL <%s> has scheme different from base <%s>\n",
301 merged_scheme = base_scheme;
if(scheme) Free(scheme);
305 merged_host = host; Free(base_host);
310 merged_host = base_host;
311 merged_port = base_port;
314 Free(path); Free(base_path);
316 merged_url = Malloc(strlen(merged_scheme) + 1 +
317 (merged_host ? 2 + strlen(merged_host) + 10 : 0) +
318 strlen(merged_path) + 1);
321 if(merged_port == -1)
322 sprintf(merged_url,
"%s://%s%s",
323 merged_scheme, merged_host, merged_path);
325 sprintf(merged_url,
"%s://%s:%d%s",
326 merged_scheme, merged_host, merged_port, merged_path);
329 sprintf(merged_url,
"%s:%s", merged_scheme, merged_path);
333 if(_scheme) *_scheme = merged_scheme;
else Free(merged_scheme);
334 if(_host) *_host = merged_host;
else Free(merged_host);
335 if(_port) *_port = merged_port;
336 if(_path) *_path = merged_path;
else Free(merged_path);
367 FILE16 *url_open(
const char *url,
const char *base,
const char *type,
370 char *scheme, *host, *path, *m_url;
374 int len, gzipped = 0;
379 if(!(m_url = url_merge(url, base, &scheme, &host, &port, &path)))
384 if(len > 3 && strcmp8(m_url+len-3,
".gz") == 0)
395 for(i=0; i<NSCHEME; i++)
396 if(strcmp(scheme, schemes[i].scheme) == 0)
398 f = schemes[i].open(m_url, host, port, path, type);
415 FILE *file = GetFILE(f);
420 "Can't attach gzip processor to URL \"%s\"\n",
426 gfile =gzdopen(dup(fileno(file)), *type ==
'r' ?
"rb" :
"wb");
428 gfile = gzdopen(dup(fileno(file)), type);
431 f = MakeFILE16FromGzip(gfile, type);
444 LT_ERROR1(LEFILE,
"Error: scheme \"%s\" not implemented\n", scheme);
457 static FILE16 *http_open(
const char *url,
458 const char *host,
int port,
const char *path,
461 #ifndef SOCKETS_IMPLEMENTED
463 "http: URLs are not yet implemented on this platform\n");
467 struct sockaddr_in addr;
468 struct hostent *hostent;
469 int s, server_major, server_minor, status, count, c;
476 static char buf[1024];
479 WORD version = MAKEWORD(1, 1);
481 int err = WSAStartup(version, &wsaData);
484 LT_ERROR(LEFILE,
"Error: can't init HTTP interface\n");
487 else if(LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1)
489 LT_ERROR(LEFILE,
"Error: wrong version of WINSOCK\n");
499 LT_ERROR1(LEFILE,
"Error: can't open http URL \"%s\" for writing\n",
506 LT_ERROR1(LEFILE,
"Error: no host part in http URL \"%s\"\n", url);
512 s = socket(PF_INET, SOCK_STREAM, 0);
514 if (s == INVALID_SOCKET) {
515 LT_ERROR1(LEFILE,
"Error: system call socket failed: %d\n",
520 LT_ERROR1(LEFILE,
"Error: system call socket failed: %s\n",
528 hostent = gethostbyname(host);
532 "Error: can't find address for host in http URL \"%s\"\n",
537 memset(&addr, 0,
sizeof(addr));
538 addr.sin_family = AF_INET;
540 memcpy(&addr.sin_addr, hostent->h_addr, hostent->h_length);
541 addr.sin_port = htons((u_short)(port == -1 ? 80 : port));
545 if(connect(s, (
struct sockaddr *)&addr,
sizeof(addr)) == -1)
547 LT_ERROR1(LEFILE,
"Error: system call connect failed: %s\n",
554 fin = fdopen(s,
"rb");
555 setvbuf(fin, 0, _IONBF, 0);
556 fout = fdopen(dup(s),
"wb");
558 fin = fdopen(s,
"r");
559 setvbuf(fin, 0, _IONBF, 0);
560 fout = fdopen(dup(s),
"w");
572 sprintf(buf,
"GET %s HTTP/1.0\012\015Connection: close\012\015\012\015",
574 if (send(s,buf,strlen8(buf),0)==SOCKET_ERROR) {
575 LT_ERROR1(LEFILE,
"Error: system call socket failed: %d\n",
581 fprintf(fout,
"GET %s HTTP/1.0\012\015Connection: close\012\015\012\015",
591 LT_ERROR1(LEWRTF,
"Error: write to socket failed: %s\n",Strerror());
601 for(i=0; i<
sizeof(buf)-1; i++)
603 if(recv(s, &buf[i], 1, 0) != 1)
605 "Error: recv error from server for URL \"%s\"\n",
610 count=sscanf(buf,
"HTTP/%d.%d %d %80[^\012]",
611 &server_major, &server_minor, &status, reason);
613 count=fscanf(fin,
"HTTP/%d.%d %d %80[^\012]",
614 &server_major, &server_minor, &status, reason);
620 "Error: bad header from server for URL \"%s\"\n%d %s\n",
621 url, count, Strerror());
631 LT_ERROR3(LEFILE,
"Error: can't retrieve \"%s\": %d %s\n",
632 url, status, reason);
643 while(recv(s, buf, 1, 0) == 1 && (c = buf[0], 1) || (c = EOF, 0))
645 while((c = getc(fin)) != EOF)
658 LT_ERROR1(LEFILE,
"Error: EOF in headers retrieving \"%s\"\n", url);
666 f16 = MakeFILE16FromWinsock(s, type);
668 f16 = MakeFILE16FromFILE(fin, type);
671 SetCloseUnderlying(f16, 1);
678 static FILE16 *file_open(
const char *url,
679 const char *host,
int port,
const char *path,
687 WARN1(LEFILE,
"Warning: ignoring host part in file URL \"%s\"\n", url);
693 if(path[0] ==
'/' && path[1] && path[2] ==
':')
696 file = strdup8(path);
712 file = strdup8(path);
723 file = strdup8(path);
730 f = fopen(file, type);
740 f16 = MakeFILE16FromFILE(f, type);
741 SetCloseUnderlying(f16, 1);
746 static void parse_url(
const char *url,
747 char **scheme,
char **host,
int *port,
char **path)
752 *scheme = *host = *path = 0;
757 for(p = (
char *)url; *p; p++)
758 if(*p ==
':' || *p ==
'/')
761 if(p > url && *p ==
':')
763 *scheme = Malloc(p - url + 1);
764 strncpy(*scheme, url, p - url);
765 (*scheme)[p - url] =
'\0';
771 if(url[0] ==
'/' && url[1] ==
'/')
775 for(p = (
char *)url; *p; p++)
781 for(q = p-1; q >= url; q--)
782 if(!isdigit((
int)*q))
785 if(q < p-1 && *q ==
':')
790 *host = Malloc(q - url + 1);
791 strncpy(*host, url, q - url);
792 (*host)[q - url] =
'\0';
799 *path = strdup8(url);
801 *path = strdup8(
"/");
805 for(p=*path; *p; p++)
810 WARN1(LEFILE,
"Warning: illegal backslashes in URL path \"%s\""
811 "replaced by slashes\n", url);