version 1.4, 1999/09/17 12:08:23
|
version 1.5, 1999/09/18 15:26:12
|
Line 1
|
Line 1
|
/* |
/* |
* nanohttp.c: minimalist HTTP implementation to fetch external subsets. |
* nanohttp.c: minimalist HTTP GET implementation to fetch external subsets. |
|
* focuses on size, streamability, reentrancy and portability |
|
* |
|
* This is clearly not a general purpose HTTP implementation |
|
* If you look for one, check: |
|
* http://www.w3.org/Library/ |
* |
* |
* See Copyright for the status of this software. |
* See Copyright for the status of this software. |
* |
* |
* Daniel.Veillard@w3.org |
* Daniel.Veillard@w3.org |
*/ |
*/ |
|
|
|
/* TODO add compression support, Send the Accept- , and decompress on the |
|
fly with ZLIB if found at compile-time */ |
|
|
#ifndef WIN32 |
#ifndef WIN32 |
#include "config.h" |
#include "config.h" |
#endif |
#endif |
Line 44
|
Line 52
|
#include <sys/select.h> |
#include <sys/select.h> |
#endif |
#endif |
|
|
|
#ifdef STANDALONE |
|
#define DEBUG_HTTP |
|
#endif |
|
|
#define XML_NANO_HTTP_MAX_REDIR 10 |
#define XML_NANO_HTTP_MAX_REDIR 10 |
|
|
#define XML_NANO_HTTP_CHUNK 4096 |
#define XML_NANO_HTTP_CHUNK 4096 |
Line 73 typedef struct xmlNanoHTTPCtxt {
|
Line 85 typedef struct xmlNanoHTTPCtxt {
|
char *location; /* the new URL in case of redirect */ |
char *location; /* the new URL in case of redirect */ |
} xmlNanoHTTPCtxt, *xmlNanoHTTPCtxtPtr; |
} xmlNanoHTTPCtxt, *xmlNanoHTTPCtxtPtr; |
|
|
static void xmlNanoHTTPScanURL(xmlNanoHTTPCtxtPtr ctxt, const char *URL) { |
/** |
|
* xmlNanoHTTPScanURL: |
|
* @ctxt: an HTTP context |
|
* @URL: The URL used to initialize the context |
|
* |
|
* (Re)Initialize an HTTP context by parsing the URL and finding |
|
* the protocol host port and path it indicates. |
|
*/ |
|
|
|
static void |
|
xmlNanoHTTPScanURL(xmlNanoHTTPCtxtPtr ctxt, const char *URL) { |
const char *cur = URL; |
const char *cur = URL; |
char buf[4096]; |
char buf[4096]; |
int index = 0; |
int index = 0; |
Line 131 static void xmlNanoHTTPScanURL(xmlNanoHT
|
Line 153 static void xmlNanoHTTPScanURL(xmlNanoHT
|
} |
} |
if (*cur == 0) |
if (*cur == 0) |
ctxt->path = strdup("/"); |
ctxt->path = strdup("/"); |
else |
else { |
|
buf[index] = 0; |
ctxt->path = strdup(cur); |
ctxt->path = strdup(cur); |
|
while (*cur != 0) { |
|
if ((cur[0] == '#') || (cur[0] == '?')) |
|
break; |
|
buf[index++] = *cur++; |
|
} |
|
buf[index] = 0; |
|
ctxt->path = strdup(buf); |
|
} |
} |
} |
|
|
static xmlNanoHTTPCtxtPtr xmlNanoHTTPNewCtxt(const char *URL) { |
/** |
|
* xmlNanoHTTPNewCtxt: |
|
* @URL: The URL used to initialize the context |
|
* |
|
* Allocate and initialize a new HTTP context. |
|
* |
|
* Returns an HTTP context or NULL in case of error. |
|
*/ |
|
|
|
static xmlNanoHTTPCtxtPtr |
|
xmlNanoHTTPNewCtxt(const char *URL) { |
xmlNanoHTTPCtxtPtr ret; |
xmlNanoHTTPCtxtPtr ret; |
|
|
ret = (xmlNanoHTTPCtxtPtr) malloc(sizeof(xmlNanoHTTPCtxt)); |
ret = (xmlNanoHTTPCtxtPtr) malloc(sizeof(xmlNanoHTTPCtxt)); |
Line 150 static xmlNanoHTTPCtxtPtr xmlNanoHTTPNew
|
Line 191 static xmlNanoHTTPCtxtPtr xmlNanoHTTPNew
|
return(ret); |
return(ret); |
} |
} |
|
|
static void xmlNanoHTTPFreeCtxt(xmlNanoHTTPCtxtPtr ctxt) { |
/** |
|
* xmlNanoHTTPFreeCtxt: |
|
* @ctxt: an HTTP context |
|
* |
|
* Frees the context after closing the connection. |
|
*/ |
|
|
|
static void |
|
xmlNanoHTTPFreeCtxt(xmlNanoHTTPCtxtPtr ctxt) { |
|
if (ctxt == NULL) return; |
if (ctxt->hostname != NULL) free(ctxt->hostname); |
if (ctxt->hostname != NULL) free(ctxt->hostname); |
if (ctxt->protocol != NULL) free(ctxt->protocol); |
if (ctxt->protocol != NULL) free(ctxt->protocol); |
if (ctxt->path != NULL) free(ctxt->path); |
if (ctxt->path != NULL) free(ctxt->path); |
Line 164 static void xmlNanoHTTPFreeCtxt(xmlNanoH
|
Line 214 static void xmlNanoHTTPFreeCtxt(xmlNanoH
|
free(ctxt); |
free(ctxt); |
} |
} |
|
|
static void xmlNanoHTTPSend(xmlNanoHTTPCtxtPtr ctxt) { |
/** |
|
* xmlNanoHTTPSend: |
|
* @ctxt: an HTTP context |
|
* |
|
* Send the input needed to initiate the processing on the server side |
|
*/ |
|
|
|
static void |
|
xmlNanoHTTPSend(xmlNanoHTTPCtxtPtr ctxt) { |
if (ctxt->state & XML_NANO_HTTP_WRITE) |
if (ctxt->state & XML_NANO_HTTP_WRITE) |
ctxt->last = write(ctxt->fd, ctxt->outptr, strlen(ctxt->outptr)); |
ctxt->last = write(ctxt->fd, ctxt->outptr, strlen(ctxt->outptr)); |
} |
} |
|
|
static int xmlNanoHTTPRecv(xmlNanoHTTPCtxtPtr ctxt) { |
/** |
|
* xmlNanoHTTPRecv: |
|
* @ctxt: an HTTP context |
|
* |
|
* Read information coming from the HTTP connection. |
|
* This is a blocking call (but it blocks in select(), not read()). |
|
* |
|
* Returns the number of byte read or -1 in case of error. |
|
*/ |
|
|
|
static int |
|
xmlNanoHTTPRecv(xmlNanoHTTPCtxtPtr ctxt) { |
fd_set rfd; |
fd_set rfd; |
struct timeval tv; |
struct timeval tv; |
|
|
Line 218 static int xmlNanoHTTPRecv(xmlNanoHTTPCt
|
Line 287 static int xmlNanoHTTPRecv(xmlNanoHTTPCt
|
} |
} |
#ifdef EWOULDBLOCK |
#ifdef EWOULDBLOCK |
if ((ctxt->last == -1) && (errno != EWOULDBLOCK)) { |
if ((ctxt->last == -1) && (errno != EWOULDBLOCK)) { |
return 0; |
return(0); |
} |
} |
#endif |
#endif |
tv.tv_sec=10; |
tv.tv_sec=10; |
Line 227 static int xmlNanoHTTPRecv(xmlNanoHTTPCt
|
Line 296 static int xmlNanoHTTPRecv(xmlNanoHTTPCt
|
FD_SET(ctxt->fd, &rfd); |
FD_SET(ctxt->fd, &rfd); |
|
|
if(select(ctxt->fd+1, &rfd, NULL, NULL, &tv)<1) |
if(select(ctxt->fd+1, &rfd, NULL, NULL, &tv)<1) |
return 0; |
return(0); |
} |
} |
return(0); |
return(0); |
} |
} |
|
|
char *xmlNanoHTTPReadLine(xmlNanoHTTPCtxtPtr ctxt) { |
/** |
static char buf[4096]; |
* xmlNanoHTTPReadLine: |
|
* @ctxt: an HTTP context |
|
* |
|
* Read one line in the HTTP server output, usually for extracting |
|
* the HTTP protocol informations from the answer header. |
|
* |
|
* Returns a newly allocated string with a copy of the line, or NULL |
|
* which indicate the end of the input. |
|
*/ |
|
|
|
static char * |
|
xmlNanoHTTPReadLine(xmlNanoHTTPCtxtPtr ctxt) { |
|
char buf[4096]; |
char *bp=buf; |
char *bp=buf; |
|
|
while(bp - buf < 4095) { |
while(bp - buf < 4095) { |
if(ctxt->inrptr == ctxt->inptr) { |
if(ctxt->inrptr == ctxt->inptr) { |
if (xmlNanoHTTPRecv(ctxt) == 0) { |
if (xmlNanoHTTPRecv(ctxt) == 0) { |
if (bp == buf) |
if (bp == buf) |
return NULL; |
return(NULL); |
else |
else |
*bp = 0; |
*bp = 0; |
return buf; |
return(strdup(buf)); |
} |
} |
} |
} |
*bp = *ctxt->inrptr++; |
*bp = *ctxt->inrptr++; |
if(*bp == '\n') { |
if(*bp == '\n') { |
*bp = 0; |
*bp = 0; |
return buf; |
return(strdup(buf)); |
} |
} |
if(*bp != '\r') |
if(*bp != '\r') |
bp++; |
bp++; |
} |
} |
buf[4095] = 0; |
buf[4095] = 0; |
return(buf); |
return(strdup(buf)); |
} |
} |
|
|
|
|
static void xmlNanoHTTPScanAnswer(xmlNanoHTTPCtxtPtr ctxt, const char *line) { |
/** |
|
* xmlNanoHTTPScanAnswer: |
|
* @ctxt: an HTTP context |
|
* @line: an HTTP header line |
|
* |
|
* Try to extract useful informations from the server answer. |
|
* We currently parse and process: |
|
* - The HTTP revision/ return code |
|
* - The Content-Type |
|
* - The Location for redirrect processing. |
|
* |
|
* Returns -1 in case of failure, the file descriptor number otherwise |
|
*/ |
|
|
|
static void |
|
xmlNanoHTTPScanAnswer(xmlNanoHTTPCtxtPtr ctxt, const char *line) { |
const char *cur = line; |
const char *cur = line; |
|
|
if (line == NULL) return; |
if (line == NULL) return; |
Line 330 static void xmlNanoHTTPScanAnswer(xmlNan
|
Line 426 static void xmlNanoHTTPScanAnswer(xmlNan
|
} |
} |
} |
} |
|
|
static int xmlNanoHTTPConnectAttempt(struct in_addr ia, int port) |
/** |
|
* xmlNanoHTTPConnectAttempt: |
|
* @ia: an internet adress structure |
|
* @port: the port number |
|
* |
|
* Attempt a connection to the given IP:port endpoint. It forces |
|
* non-blocking semantic on the socket, and allow 60 seconds for |
|
* the host to answer. |
|
* |
|
* Returns -1 in case of failure, the file descriptor number otherwise |
|
*/ |
|
|
|
static int |
|
xmlNanoHTTPConnectAttempt(struct in_addr ia, int port) |
{ |
{ |
int s=socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); |
int s=socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); |
struct sockaddr_in sin; |
struct sockaddr_in sin; |
Line 339 static int xmlNanoHTTPConnectAttempt(str
|
Line 448 static int xmlNanoHTTPConnectAttempt(str
|
int status; |
int status; |
|
|
if(s==-1) { |
if(s==-1) { |
|
#ifdef DEBUG_HTTP |
perror("socket"); |
perror("socket"); |
|
#endif |
return(-1); |
return(-1); |
} |
} |
|
|
Line 370 static int xmlNanoHTTPConnectAttempt(str
|
Line 481 static int xmlNanoHTTPConnectAttempt(str
|
status = fcntl(s, F_SETFL, status); |
status = fcntl(s, F_SETFL, status); |
} |
} |
if(status < 0) { |
if(status < 0) { |
|
#ifdef DEBUG_HTTP |
perror("nonblocking"); |
perror("nonblocking"); |
|
#endif |
close(s); |
close(s); |
return(-1); |
return(-1); |
} |
} |
Line 403 static int xmlNanoHTTPConnectAttempt(str
|
Line 516 static int xmlNanoHTTPConnectAttempt(str
|
return(-1); |
return(-1); |
case -1: |
case -1: |
/* Ermm.. ?? */ |
/* Ermm.. ?? */ |
|
#ifdef DEBUG_HTTP |
perror("select"); |
perror("select"); |
|
#endif |
close(s); |
close(s); |
return(-1); |
return(-1); |
} |
} |
|
|
return s; |
return(s); |
} |
} |
|
|
int xmlNanoHTTPConnectHost(const char *host, int port) |
/** |
|
* xmlNanoHTTPConnectHost: |
|
* @host: the host name |
|
* @port: the port number |
|
* |
|
* Attempt a connection to the given host:port endpoint. It tries |
|
* the multiple IP provided by the DNS if available. |
|
* |
|
* Returns -1 in case of failure, the file descriptor number otherwise |
|
*/ |
|
|
|
static int |
|
xmlNanoHTTPConnectHost(const char *host, int port) |
{ |
{ |
struct hostent *h; |
struct hostent *h; |
int i; |
int i; |
Line 420 int xmlNanoHTTPConnectHost(const char *h
|
Line 547 int xmlNanoHTTPConnectHost(const char *h
|
h=gethostbyname(host); |
h=gethostbyname(host); |
if(h==NULL) |
if(h==NULL) |
{ |
{ |
|
#ifdef DEBUG_HTTP |
fprintf(stderr,"unable to resolve '%s'.\n", host); |
fprintf(stderr,"unable to resolve '%s'.\n", host); |
|
#endif |
return(-1); |
return(-1); |
} |
} |
|
|
|
|
for(i=0; h->h_addr_list[i]; i++) |
for(i=0; h->h_addr_list[i]; i++) |
{ |
{ |
struct in_addr ia; |
struct in_addr ia; |
memcpy(&ia, h->h_addr_list[i],4); |
memcpy(&ia, h->h_addr_list[i],4); |
s = xmlNanoHTTPConnectAttempt(ia, port); |
s = xmlNanoHTTPConnectAttempt(ia, port); |
if(s != -1) |
if(s != -1) |
return s; |
return(s); |
} |
} |
|
|
|
#ifdef DEBUG_HTTP |
fprintf(stderr, "unable to connect to '%s'.\n", host); |
fprintf(stderr, "unable to connect to '%s'.\n", host); |
|
#endif |
return(-1); |
return(-1); |
} |
} |
|
|
int xmlNanoHTTPOldFetch(const char *URL, const char *filename, |
|
char **contentType) { |
|
xmlNanoHTTPCtxtPtr ctxt; |
|
char buf[4096]; |
|
int ret; |
|
int fd; |
|
char *p; |
|
int head; |
|
int nbRedirects = 0; |
|
char *redirURL = NULL; |
|
|
|
retry: |
|
if (redirURL == NULL) |
|
ctxt = xmlNanoHTTPNewCtxt(URL); |
|
else |
|
ctxt = xmlNanoHTTPNewCtxt(redirURL); |
|
|
|
if ((ctxt->protocol == NULL) || (strcmp(ctxt->protocol, "http"))) { |
/** |
xmlNanoHTTPFreeCtxt(ctxt); |
* xmlNanoHTTPOpen: |
if (redirURL != NULL) free(redirURL); |
* @URL: The URL to load |
return(-1); |
* @contentType: if available the Content-Type information will be |
} |
* returned at that location |
if (ctxt->hostname == NULL) { |
* |
xmlNanoHTTPFreeCtxt(ctxt); |
* This function try to open a connection to the indicated resource |
if (redirURL != NULL) free(redirURL); |
* via HTTP GET. |
return(-1); |
* |
} |
* Returns -1 in case of failure, 0 incase of success. The contentType, |
ret = xmlNanoHTTPConnectHost(ctxt->hostname, ctxt->port); |
* if provided must be freed by the caller |
if (ret < 0) { |
*/ |
xmlNanoHTTPFreeCtxt(ctxt); |
|
if (redirURL != NULL) free(redirURL); |
|
return(-1); |
|
} |
|
ctxt->fd = ret; |
|
snprintf(buf, sizeof(buf),"GET %s HTTP/1.0\r\nhost: %s\r\n\r\n", |
|
ctxt->path, ctxt->hostname); |
|
ctxt->outptr = ctxt->out = strdup(buf); |
|
ctxt->state = XML_NANO_HTTP_WRITE; |
|
xmlNanoHTTPSend(ctxt); |
|
ctxt->state = XML_NANO_HTTP_READ; |
|
head = 1; |
|
|
|
while ((p = xmlNanoHTTPReadLine(ctxt)) != NULL) { |
|
if (head && (*p == 0)) { |
|
head = 0; |
|
ctxt->content = ctxt->inrptr; |
|
break; |
|
} |
|
xmlNanoHTTPScanAnswer(ctxt, p); |
|
if (p != NULL) printf("%s\n", p); |
|
} |
|
while (xmlNanoHTTPRecv(ctxt)) ; |
|
|
|
if (!strcmp(filename, "-")) |
|
fd = 0; |
|
else { |
|
fd = open(filename, O_CREAT | O_WRONLY); |
|
if (fd < 0) { |
|
xmlNanoHTTPFreeCtxt(ctxt); |
|
if (redirURL != NULL) free(redirURL); |
|
return(-1); |
|
} |
|
} |
|
|
|
printf("Code %d, content-type '%s'\n\n", |
|
ctxt->returnValue, ctxt->contentType); |
|
if ((ctxt->location != NULL) && (ctxt->returnValue >= 300) && |
|
(ctxt->returnValue < 400)) { |
|
printf("Redirect to: %s\n", ctxt->location); |
|
if (nbRedirects < XML_NANO_HTTP_MAX_REDIR) { |
|
nbRedirects++; |
|
if (redirURL != NULL) free(redirURL); |
|
redirURL = strdup(ctxt->location); |
|
xmlNanoHTTPFreeCtxt(ctxt); |
|
goto retry; |
|
} |
|
} |
|
|
|
write(fd, ctxt->content, ctxt->inptr - ctxt->content); |
|
xmlNanoHTTPFreeCtxt(ctxt); |
|
if (redirURL != NULL) free(redirURL); |
|
return(0); |
|
} |
|
|
|
void * |
void * |
xmlNanoHTTPOpen(const char *URL, char **contentType) { |
xmlNanoHTTPOpen(const char *URL, char **contentType) { |
Line 531 xmlNanoHTTPOpen(const char *URL, char **
|
Line 592 xmlNanoHTTPOpen(const char *URL, char **
|
int nbRedirects = 0; |
int nbRedirects = 0; |
char *redirURL = NULL; |
char *redirURL = NULL; |
|
|
|
if (contentType != NULL) *contentType = NULL; |
|
|
retry: |
retry: |
if (redirURL == NULL) |
if (redirURL == NULL) |
ctxt = xmlNanoHTTPNewCtxt(URL); |
ctxt = xmlNanoHTTPNewCtxt(URL); |
Line 555 retry:
|
Line 618 retry:
|
return(NULL); |
return(NULL); |
} |
} |
ctxt->fd = ret; |
ctxt->fd = ret; |
snprintf(buf, sizeof(buf),"GET %s HTTP/1.0\r\nhost: %s\r\n\r\n", |
snprintf(buf, sizeof(buf),"GET %s HTTP/1.0\r\nHost: %s\r\n\r\n", |
ctxt->path, ctxt->hostname); |
ctxt->path, ctxt->hostname); |
|
#ifdef DEBUG_HTTP |
|
printf("-> GET %s HTTP/1.0\n-> Host: %s\n\n", |
|
ctxt->path, ctxt->hostname); |
|
#endif |
ctxt->outptr = ctxt->out = strdup(buf); |
ctxt->outptr = ctxt->out = strdup(buf); |
ctxt->state = XML_NANO_HTTP_WRITE; |
ctxt->state = XML_NANO_HTTP_WRITE; |
xmlNanoHTTPSend(ctxt); |
xmlNanoHTTPSend(ctxt); |
Line 571 retry:
|
Line 638 retry:
|
} |
} |
xmlNanoHTTPScanAnswer(ctxt, p); |
xmlNanoHTTPScanAnswer(ctxt, p); |
|
|
if (p != NULL) printf("%s\n", p); |
#ifdef DEBUG_HTTP |
|
if (p != NULL) printf("<- %s\n", p); |
|
#endif |
|
if (p != NULL) free(p); |
} |
} |
|
|
if ((ctxt->location != NULL) && (ctxt->returnValue >= 300) && |
if ((ctxt->location != NULL) && (ctxt->returnValue >= 300) && |
(ctxt->returnValue < 400)) { |
(ctxt->returnValue < 400)) { |
printf("Redirect to: %s\n", ctxt->location); |
#ifdef DEBUG_HTTP |
|
printf("\nRedirect to: %s\n", ctxt->location); |
|
#endif |
while (xmlNanoHTTPRecv(ctxt)) ; |
while (xmlNanoHTTPRecv(ctxt)) ; |
if (nbRedirects < XML_NANO_HTTP_MAX_REDIR) { |
if (nbRedirects < XML_NANO_HTTP_MAX_REDIR) { |
nbRedirects++; |
nbRedirects++; |
Line 585 printf("Redirect to: %s\n", ctxt->locati
|
Line 657 printf("Redirect to: %s\n", ctxt->locati
|
goto retry; |
goto retry; |
} |
} |
xmlNanoHTTPFreeCtxt(ctxt); |
xmlNanoHTTPFreeCtxt(ctxt); |
|
#ifdef DEBUG_HTTP |
|
printf("Too many redirrects, aborting ...\n"); |
|
#endif |
return(NULL); |
return(NULL); |
|
|
} |
} |
|
|
printf("Code %d, content-type '%s'\n\n", |
if ((contentType != NULL) && (ctxt->contentType != NULL)) |
ctxt->returnValue, ctxt->contentType); |
*contentType = strdup(ctxt->contentType); |
|
|
|
#ifdef DEBUG_HTTP |
|
if (ctxt->contentType != NULL) |
|
printf("\nCode %d, content-type '%s'\n\n", |
|
ctxt->returnValue, ctxt->contentType); |
|
else |
|
printf("\nCode %d, no content-type\n\n", |
|
ctxt->returnValue); |
|
#endif |
|
|
return((void *) ctxt); |
return((void *) ctxt); |
} |
} |
|
|
|
/** |
|
* xmlNanoHTTPRead: |
|
* @ctx: the HTTP context |
|
* @dest: a buffer |
|
* @len: the buffer length |
|
* |
|
* This function tries to read @len bytes from the existing HTTP connection |
|
* and saves them in @dest. This is a blocking call. |
|
* |
|
* Returns the number of byte read. 0 is an indication of an end of connection. |
|
* -1 indicates a parameter error. |
|
*/ |
int |
int |
xmlNanoHTTPRead(void *ctx, void *dest, int len) { |
xmlNanoHTTPRead(void *ctx, void *dest, int len) { |
xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr) ctx; |
xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr) ctx; |
Line 613 xmlNanoHTTPRead(void *ctx, void *dest, i
|
Line 709 xmlNanoHTTPRead(void *ctx, void *dest, i
|
return(len); |
return(len); |
} |
} |
|
|
|
/** |
|
* xmlNanoHTTPClose: |
|
* @ctx: the HTTP context |
|
* |
|
* This function closes an HTTP context, it ends up the connection and |
|
* free all data related to it. |
|
*/ |
void |
void |
xmlNanoHTTPClose(void *ctx) { |
xmlNanoHTTPClose(void *ctx) { |
xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr) ctx; |
xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr) ctx; |
Line 622 xmlNanoHTTPClose(void *ctx) {
|
Line 725 xmlNanoHTTPClose(void *ctx) {
|
xmlNanoHTTPFreeCtxt(ctxt); |
xmlNanoHTTPFreeCtxt(ctxt); |
} |
} |
|
|
int xmlNanoHTTPFetch(const char *URL, const char *filename, |
/** |
char **contentType) { |
* xmlNanoHTTPFetch: |
|
* @URL: The URL to load |
|
* @filename: the filename where the content should be saved |
|
* @contentType: if available the Content-Type information will be |
|
* returned at that location |
|
* |
|
* This function try to fetch the indicated resource via HTTP GET |
|
* and save it's content in the file. |
|
* |
|
* Returns -1 in case of failure, 0 incase of success. The contentType, |
|
* if provided must be freed by the caller |
|
*/ |
|
int |
|
xmlNanoHTTPFetch(const char *URL, const char *filename, char **contentType) { |
void *ctxt; |
void *ctxt; |
char buf[4096]; |
char buf[4096]; |
int fd; |
int fd; |
Line 638 int xmlNanoHTTPFetch(const char *URL, co
|
Line 754 int xmlNanoHTTPFetch(const char *URL, co
|
fd = open(filename, O_CREAT | O_WRONLY); |
fd = open(filename, O_CREAT | O_WRONLY); |
if (fd < 0) { |
if (fd < 0) { |
xmlNanoHTTPClose(ctxt); |
xmlNanoHTTPClose(ctxt); |
|
if ((contentType != NULL) && (*contentType != NULL)) { |
|
free(*contentType); |
|
*contentType = NULL; |
|
} |
return(-1); |
return(-1); |
} |
} |
} |
} |
Line 659 int main(int argc, char **argv) {
|
Line 779 int main(int argc, char **argv) {
|
xmlNanoHTTPFetch(argv[1], argv[2], &contentType); |
xmlNanoHTTPFetch(argv[1], argv[2], &contentType); |
else |
else |
xmlNanoHTTPFetch(argv[1], "-", &contentType); |
xmlNanoHTTPFetch(argv[1], "-", &contentType); |
|
if (contentType != NULL) free(contentType); |
} else { |
} else { |
printf("%s: minimal HTTP GET implementation\n", argv[0]); |
printf("%s: minimal HTTP GET implementation\n", argv[0]); |
printf("\tusage %s [ URL [ filename ] ]\n", argv[0]); |
printf("\tusage %s [ URL [ filename ] ]\n", argv[0]); |