19 #include "lt-memory.h" 20 #include "lt-errmsg.h" 21 #include "lt-comment.h" 25 #define Strerror() strErr() 27 #define Realloc srealloc 29 #define fopen stdsfopen 35 #define LT_ERROR(err, format) fprintf(stderr, format) 36 #define LT_ERROR1(err, format, arg) fprintf(stderr, format, arg) 37 #define LT_ERROR2(err, format, arg1, arg2) fprintf(stderr, format, arg1, arg2) 38 #define LT_ERROR3(err, format, arg1, arg2, arg3) fprintf(stderr, format, arg1, arg2, arg3) 39 #define WARN(err, format) fprintf(stderr, format) 40 #define WARN1(err, format, arg) fprintf(stderr, format, arg) 42 #define Strerror() strerror(errno) 45 #define CWDBS MAXPATHLEN+1 50 #define GETWD(buf) getcwd(buf,CWDBS) 60 #include <sys/types.h> 66 #ifdef SOCKETS_IMPLEMENTED 75 #include <sys/socket.h> 76 #include <netinet/in.h> 93 static FILE16 *http_open(
const char *url,
94 const char *host,
int port,
const char *path,
96 static FILE16 *file_open(
const char *url,
97 const char *host,
int port,
const char *path,
101 char **
scheme,
char **host,
int *port,
char **path);
107 FILE16 *(*open)(
const char *,
const char *,
int,
const char *,
const char *);
109 {(
char *)
"http", http_open},
110 {(
char *)
"file", file_open},
112 #define NSCHEME (sizeof(schemes) / sizeof(schemes[0])) 123 WARN(LEFILE,
"Warning: can't get current directory for default base url\n");
138 url =
Malloc(6 + strlen(buf) + 2);
142 sprintf(url,
"file:/%s/", buf);
158 url =
Malloc(6 + strlen(buf) + 2);
162 sprintf(url,
"file:/%s/", buf);
168 url =
Malloc(5 + strlen(buf) + 2);
172 sprintf(url,
"file:%s/", buf);
189 char **_scheme,
char **_host,
int *_port,
char **_path)
191 char *merged_scheme, *merged_host, *merged_path, *merged_url;
192 char *
scheme=0, *host=0, *path=0;
193 char *base_scheme=0, *base_host=0, *base_path=0;
194 char *default_base=0;
195 int port, base_port, merged_port, i, j;
200 if (
parse_url(url, &scheme, &host, &port, &path) < 0) {
203 if(scheme && (host || *path ==
'/'))
218 if (
parse_url(base, &base_scheme, &base_host, &base_port, &base_path) < 0) {
221 if(base_scheme && (base_host || *base_path ==
'/'))
225 LT_ERROR1(LEFILE,
"Error: bad base URL <%s>\n", base);
241 merged_path =
Malloc(strlen(base_path) + strlen(path) + 1);
242 strcpy(merged_path, base_path);
246 for(i=strlen(merged_path)-1; i>=0 && merged_path[i] !=
'/'; i--)
247 merged_path[i] =
'\0';
251 strcat(merged_path, path);
262 for(j=i+1; p[j] && p[j] !=
'/'; j++)
267 if(j - i == 2 && p[i+1] ==
'.')
269 strcpy(&p[i+1], p[j] ? &p[j+1] : &p[j]);
279 if(p[j] ==
'/' && p[j+1] ==
'.' && p[j+2] ==
'.' &&
280 (p[j+3] ==
'/' || p[j+3] ==
'\0') &&
281 (j - i != 3 || p[i+1] !=
'.' || p[i+2] !=
'.'))
283 strcpy(&p[i+1], p[j+3] ? &p[j+4] : &p[j+3]);
296 if(scheme && !host && *path !=
'/')
298 if(strcmp(scheme, base_scheme) == 0)
301 "Warning: relative URL <%s> contains scheme, contrary to RFC 1808\n",
307 "Error: relative URL <%s> has scheme different from base <%s>\n",
316 merged_scheme = base_scheme;
if(scheme)
Free(scheme);
320 merged_host = host;
Free(base_host);
325 merged_host = base_host;
326 merged_port = base_port;
331 merged_url =
Malloc(strlen(merged_scheme) + 1 +
332 (merged_host ? 2 + strlen(merged_host) + 10 : 0) +
333 strlen(merged_path) + 1);
334 if (merged_url ==
NULL) {
339 if(merged_port == -1)
340 sprintf(merged_url,
"%s://%s%s",
341 merged_scheme, merged_host, merged_path);
343 sprintf(merged_url,
"%s://%s:%d%s",
344 merged_scheme, merged_host, merged_port, merged_path);
347 sprintf(merged_url,
"%s:%s", merged_scheme, merged_path);
351 if(_scheme) *_scheme = merged_scheme;
else Free(merged_scheme);
352 if(_host) *_host = merged_host;
else Free(merged_host);
353 if(_port) *_port = merged_port;
354 if(_path) *_path = merged_path;
else Free(merged_path);
385 FILE16 *
url_open(
const char *url,
const char *base,
const char *type,
393 int len, gzipped = 0;
398 if(!(m_url =
url_merge(url, base, &scheme, &host, &port, &path))) {
406 if(len > 3 &&
strcmp8(m_url+len-3,
".gz") == 0)
418 if(strcmp(scheme,
schemes[i].scheme) == 0)
420 f =
schemes[i].open(m_url, host, port, path, type);
442 "Can't attach gzip processor to URL \"%s\"\n",
448 gfile =gzdopen(dup(fileno(file)), *type ==
'r' ?
"rb" :
"wb");
450 gfile = gzdopen(dup(fileno(file)), type);
453 f = MakeFILE16FromGzip(gfile, type);
466 LT_ERROR1(LEFILE,
"Error: scheme \"%s\" not implemented\n", scheme);
479 static FILE16 *http_open(
const char *url,
480 const char *host,
int port,
const char *path,
483 #ifndef SOCKETS_IMPLEMENTED 485 "http: URLs are not yet implemented on this platform\n");
489 struct sockaddr_in addr;
490 struct hostent *hostent;
491 int s, server_major, server_minor, status, count, c;
498 static char buf[1024];
501 WORD version = MAKEWORD(1, 1);
503 int err = WSAStartup(version, &wsaData);
506 LT_ERROR(LEFILE,
"Error: can't init HTTP interface\n");
509 else if(LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1)
511 LT_ERROR(LEFILE,
"Error: wrong version of WINSOCK\n");
521 LT_ERROR1(LEFILE,
"Error: can't open http URL \"%s\" for writing\n",
528 LT_ERROR1(LEFILE,
"Error: no host part in http URL \"%s\"\n", url);
534 s = socket(PF_INET, SOCK_STREAM, 0);
536 if (s == INVALID_SOCKET) {
537 LT_ERROR1(LEFILE,
"Error: system call socket failed: %d\n",
542 LT_ERROR1(LEFILE,
"Error: system call socket failed: %s\n",
550 hostent = gethostbyname(host);
554 "Error: can't find address for host in http URL \"%s\"\n",
560 memset(&addr, 0,
sizeof(addr));
561 addr.sin_family = AF_INET;
563 memcpy(&addr.sin_addr, hostent->h_addr_list[0], hostent->h_length);
564 addr.sin_port = htons((uint16_t)(port == -1 ? 80 : port));
568 if(connect(s, (
struct sockaddr *)&addr,
sizeof(addr)) == -1)
570 LT_ERROR1(LEFILE,
"Error: system call connect failed: %s\n",
578 fin = fdopen(s,
"rb");
579 setvbuf(fin, 0, _IONBF, 0);
580 fout = fdopen(dup(s),
"wb");
582 fin = fdopen(s,
"r");
583 setvbuf(fin, 0, _IONBF, 0);
587 "Error: http_open: Can't copy file descriptor\n");
592 fout = fdopen(newfd,
"w");
604 sprintf(buf,
"GET %s HTTP/1.0\012\015Connection: close\012\015\012\015",
606 if (send(s,buf,
strlen8(buf),0)==SOCKET_ERROR) {
607 LT_ERROR1(LEFILE,
"Error: system call socket failed: %d\n",
613 fprintf(fout,
"GET %s HTTP/1.0\012\015Connection: close\012\015\012\015",
633 for(i=0; i<
sizeof(buf)-1; i++)
635 if(recv(s, &buf[i], 1, 0) != 1)
637 "Error: recv error from server for URL \"%s\"\n",
642 count=sscanf(buf,
"HTTP/%d.%d %d %80[^\012]",
643 &server_major, &server_minor, &status, reason);
645 count=fscanf(fin,
"HTTP/%d.%d %d %80[^\012]",
646 &server_major, &server_minor, &status, reason);
652 "Error: bad header from server for URL \"%s\"\n%d %s\n",
663 LT_ERROR3(LEFILE,
"Error: can't retrieve \"%s\": %d %s\n",
664 url, status, reason);
675 while(recv(s, buf, 1, 0) == 1 && (c = buf[0], 1) || (c = EOF, 0))
677 while((c = getc(fin)) != EOF)
690 LT_ERROR1(LEFILE,
"Error: EOF in headers retrieving \"%s\"\n", url);
698 f16 = MakeFILE16FromWinsock(s, type);
710 static FILE16 *file_open(
const char *url,
711 const char *host,
int port,
const char *path,
719 WARN1(LEFILE,
"Warning: ignoring host part in file URL \"%s\"\n", url);
725 if(path[0] ==
'/' && path[1] && path[2] ==
':')
762 f = fopen(file, type);
779 char **
scheme,
char **host,
int *port,
char **path)
784 *
scheme = *host = *path = 0;
789 for(p = (
char *)url; *p; p++)
790 if(*p ==
':' || *p ==
'/')
793 if(p > url && *p ==
':')
799 strncpy(*
scheme, url, p - url);
800 (*scheme)[p - url] =
'\0';
806 if(url[0] ==
'/' && url[1] ==
'/')
810 for(p = (
char *)url; *p; p++)
816 for(q = p-1; q >= url; q--)
817 if(!isdigit((
int)*q))
820 if(q < p-1 && *q ==
':')
825 *host =
Malloc(q - url + 1);
829 strncpy(*host, url, q - url);
830 (*host)[q - url] =
'\0';
843 for(p=*path; *p; p++)
848 WARN1(LEFILE,
"Warning: illegal backslashes in URL path \"%s\"" 849 "replaced by slashes\n", url);
char * default_base_url(void)
#define WARN1(err, format, arg)
#define LT_ERROR3(err, format, arg1, arg2, arg3)
#define LT_ERROR1(err, format, arg)
STD_API FILE16 * MakeFILE16FromFILE(FILE *f, const char *type)
STD_API void SetCloseUnderlying(FILE16 *file, int cu)
#define WARN(err, format)
char * url_merge(const char *url, const char *base, char **_scheme, char **_host, int *_port, char **_path)
FILE16 * url_open(const char *url, const char *base, const char *type, char **merged_url)
void err(const char *message, LISP x) EST_NORETURN
#define LT_ERROR2(err, format, arg1, arg2)
STD_API FILE * GetFILE(FILE16 *file)
#define LT_ERROR(err, format)
STD_API int Fclose(FILE16 *file)
STD_API char8 * strdup8(const char8 *s)
int parse_url(const EST_String &url, EST_String &protocol, EST_String &host, EST_String &port, EST_String &path)