📄 nanohttp.c
字号:
#endif /* !_WINSOCKAPI_ */ sin.sin_family = AF_INET; sin.sin_addr = ia; sin.sin_port = htons(port); if((connect(s, (struct sockaddr *)&sin, sizeof(sin))==-1) && (errno != EINPROGRESS)) { perror("connect"); close(s); return(-1); } tv.tv_sec = 60; /* We use 60 second timeouts for now */ tv.tv_usec = 0; FD_ZERO(&wfd); FD_SET(s, &wfd); switch(select(s+1, NULL, &wfd, NULL, &tv)) { case 0: /* Time out */ close(s); return(-1); case -1: /* Ermm.. ?? */#ifdef DEBUG_HTTP perror("select");#endif close(s); return(-1); } return(s);} /** * 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 intxmlNanoHTTPConnectHost(const char *host, int port){ struct hostent *h; int i; int s; h=gethostbyname(host); if(h==NULL) {#ifdef DEBUG_HTTP fprintf(stderr,"unable to resolve '%s'.\n", host);#endif return(-1); } for(i=0; h->h_addr_list[i]; i++) { struct in_addr ia; memcpy(&ia, h->h_addr_list[i],4); s = xmlNanoHTTPConnectAttempt(ia, port); if(s != -1) return(s); }#ifdef DEBUG_HTTP fprintf(stderr, "unable to connect to '%s'.\n", host);#endif return(-1);}/** * xmlNanoHTTPOpen: * @URL: The URL to load * @contentType: if available the Content-Type information will be * returned at that location * * This function try to open a connection to the indicated resource * via HTTP GET. * * Returns NULL in case of failure, otherwise a request handler. * The contentType, if provided must be freed by the caller */void *xmlNanoHTTPOpen(const char *URL, char **contentType) { xmlNanoHTTPCtxtPtr ctxt; char buf[4096]; int ret; char *p; int head; int nbRedirects = 0; char *redirURL = NULL; xmlNanoHTTPInit(); if (contentType != NULL) *contentType = NULL;retry: if (redirURL == NULL) ctxt = xmlNanoHTTPNewCtxt(URL); else { ctxt = xmlNanoHTTPNewCtxt(redirURL); xmlFree(redirURL); redirURL = NULL; } if ((ctxt->protocol == NULL) || (strcmp(ctxt->protocol, "http"))) { xmlNanoHTTPFreeCtxt(ctxt); if (redirURL != NULL) xmlFree(redirURL); return(NULL); } if (ctxt->hostname == NULL) { xmlNanoHTTPFreeCtxt(ctxt); return(NULL); } if (proxy) ret = xmlNanoHTTPConnectHost(proxy, proxyPort); else ret = xmlNanoHTTPConnectHost(ctxt->hostname, ctxt->port); if (ret < 0) { xmlNanoHTTPFreeCtxt(ctxt); return(NULL); } ctxt->fd = ret; if (proxy) {#ifdef HAVE_SNPRINTF if (ctxt->port != 80) snprintf(buf, sizeof(buf), "GET http://%s:%d%s HTTP/1.0\r\nHost: %s\r\n\r\n", ctxt->hostname, ctxt->port, ctxt->path, ctxt->hostname); else snprintf(buf, sizeof(buf),"GET http://%s%s HTTP/1.0\r\nHost: %s\r\n\r\n", ctxt->hostname, ctxt->path, ctxt->hostname);#else if (ctxt->port != 80) sprintf(buf, "GET http://%s:%d%s HTTP/1.0\r\nHost: %s\r\n\r\n", ctxt->hostname, ctxt->port, ctxt->path, ctxt->hostname); else sprintf(buf, "GET http://%s%s HTTP/1.0\r\nHost: %s\r\n\r\n", ctxt->hostname, ctxt->path, ctxt->hostname);#endif#ifdef DEBUG_HTTP if (ctxt->port != 80) printf("-> Proxy GET http://%s:%d%s HTTP/1.0\n-> Host: %s\n\n", ctxt->hostname, ctxt->port, ctxt->path, ctxt->hostname); else printf("-> Proxy GET http://%s%s HTTP/1.0\n-> Host: %s\n\n", ctxt->hostname, ctxt->path, ctxt->hostname);#endif } else {#ifdef HAVE_SNPRINTF snprintf(buf, sizeof(buf),"GET %s HTTP/1.0\r\nHost: %s\r\n\r\n", ctxt->path, ctxt->hostname);#else sprintf(buf, "GET %s HTTP/1.0\r\nHost: %s\r\n\r\n", ctxt->path, ctxt->hostname);#endif#ifdef DEBUG_HTTP printf("-> GET %s HTTP/1.0\n-> Host: %s\n\n", ctxt->path, ctxt->hostname);#endif } ctxt->outptr = ctxt->out = xmlMemStrdup(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; xmlFree(p); break; } xmlNanoHTTPScanAnswer(ctxt, p);#ifdef DEBUG_HTTP if (p != NULL) printf("<- %s\n", p);#endif if (p != NULL) xmlFree(p); } if ((ctxt->location != NULL) && (ctxt->returnValue >= 300) && (ctxt->returnValue < 400)) {#ifdef DEBUG_HTTP printf("\nRedirect to: %s\n", ctxt->location);#endif while (xmlNanoHTTPRecv(ctxt)) ; if (nbRedirects < XML_NANO_HTTP_MAX_REDIR) { nbRedirects++; redirURL = xmlMemStrdup(ctxt->location); xmlNanoHTTPFreeCtxt(ctxt); goto retry; } xmlNanoHTTPFreeCtxt(ctxt);#ifdef DEBUG_HTTP printf("Too many redirrects, aborting ...\n");#endif return(NULL); } if ((contentType != NULL) && (ctxt->contentType != NULL)) *contentType = xmlMemStrdup(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);}/** * 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. */intxmlNanoHTTPRead(void *ctx, void *dest, int len) { xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr) ctx; if (ctx == NULL) return(-1); if (dest == NULL) return(-1); if (len <= 0) return(0); while (ctxt->inptr - ctxt->inrptr < len) { if (xmlNanoHTTPRecv(ctxt) == 0) break; } if (ctxt->inptr - ctxt->inrptr < len) len = ctxt->inptr - ctxt->inrptr; memcpy(dest, ctxt->inrptr, len); ctxt->inrptr += 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. */voidxmlNanoHTTPClose(void *ctx) { xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr) ctx; if (ctx == NULL) return; xmlNanoHTTPFreeCtxt(ctxt);}#ifndef DEBUG_HTTP#define DEBUG_HTTP#endif/** * xmlNanoHTTPMethod: * @URL: The URL to load * @method: the HTTP method to use * @input: the input string if any * @contentType: the Content-Type information IN and OUT * @headers: the extra headers * * This function try to open a connection to the indicated resource * via HTTP using the given @method, adding the given extra headers * and the input buffer for the request content. * * Returns NULL in case of failure, otherwise a request handler. * The contentType, if provided must be freed by the caller */void *xmlNanoHTTPMethod(const char *URL, const char *method, const char *input, char **contentType, const char *headers) { xmlNanoHTTPCtxtPtr ctxt; char buf[20000]; int ret; char *p; int head; int nbRedirects = 0; char *redirURL = NULL; if (URL == NULL) return(NULL); if (method == NULL) method = "GET"; if (contentType != NULL) *contentType = NULL;retry: if (redirURL == NULL) ctxt = xmlNanoHTTPNewCtxt(URL); else { ctxt = xmlNanoHTTPNewCtxt(redirURL); xmlFree(redirURL); redirURL = NULL; } if ((ctxt->protocol == NULL) || (strcmp(ctxt->protocol, "http"))) { xmlNanoHTTPFreeCtxt(ctxt); if (redirURL != NULL) xmlFree(redirURL); return(NULL); } if (ctxt->hostname == NULL) { xmlNanoHTTPFreeCtxt(ctxt); return(NULL); } ret = xmlNanoHTTPConnectHost(ctxt->hostname, ctxt->port); if (ret < 0) { xmlNanoHTTPFreeCtxt(ctxt); return(NULL); } ctxt->fd = ret; if (input == NULL) { if (headers == NULL) { if ((contentType == NULL) || (*contentType == NULL)) {#ifdef HAVE_SNPRINTF snprintf(buf, sizeof(buf), "%s %s HTTP/1.0\r\nHost: %s\r\n\r\n", method, ctxt->path, ctxt->hostname);#else sprintf(buf, "%s %s HTTP/1.0\r\nHost: %s\r\n\r\n", method, ctxt->path, ctxt->hostname);#endif } else {#ifdef HAVE_SNPRINTF snprintf(buf, sizeof(buf), "%s %s HTTP/1.0\r\nHost: %s\r\nContent-Type: %s\r\n\r\n", method, ctxt->path, ctxt->hostname, *contentType);#else sprintf(buf, "%s %s HTTP/1.0\r\nHost: %s\r\nContent-Type: %s\r\n\r\n", method, ctxt->path, ctxt->hostname, *contentType);#endif } } else { if ((contentType == NULL) || (*contentType == NULL)) {#ifdef HAVE_SNPRINTF snprintf(buf, sizeof(buf), "%s %s HTTP/1.0\r\nHost: %s\r\n%s\r\n", method, ctxt->path, ctxt->hostname, headers);#else sprintf(buf, "%s %s HTTP/1.0\r\nHost: %s\r\n%s\r\n", method, ctxt->path, ctxt->hostname, headers);#endif } else {#ifdef HAVE_SNPRINTF snprintf(buf, sizeof(buf), "%s %s HTTP/1.0\r\nHost: %s\r\nContent-Type: %s\r\n%s\r\n", method, ctxt->path, ctxt->hostname, *contentType, headers);#else sprintf(buf, "%s %s HTTP/1.0\r\nHost: %s\r\nContent-Type: %s\r\n%s\r\n", method, ctxt->path, ctxt->hostname, *contentType, headers);#endif } } } else { int len = strlen(input); if (headers == NULL) { if ((contentType == NULL) || (*contentType == NULL)) {#ifdef HAVE_SNPRINTF snprintf(buf, sizeof(buf), "%s %s HTTP/1.0\r\nHost: %s\r\nContent-Length: %d\r\n\r\n%s", method, ctxt->path, ctxt->hostname, len, input);#else sprintf(buf, "%s %s HTTP/1.0\r\nHost: %s\r\nContent-Length: %d\r\n\r\n%s", method, ctxt->path, ctxt->hostname, len, input);#endif } else {#ifdef HAVE_SNPRINTF snprintf(buf, sizeof(buf),"%s %s HTTP/1.0\r\nHost: %s\r\nContent-Type: %s\r\nContent-Length: %d\r\n\r\n%s", method, ctxt->path, ctxt->hostname, *contentType, len, input);#else sprintf(buf,"%s %s HTTP/1.0\r\nHost: %s\r\nContent-Type: %s\r\nContent-Length: %d\r\n\r\n%s", method, ctxt->path, ctxt->hostname, *contentType, len, input);#endif } } else { if ((contentType == NULL) || (*contentType == NULL)) {#ifdef HAVE_SNPRINTF snprintf(buf, sizeof(buf), "%s %s HTTP/1.0\r\nHost: %s\r\nContent-Length: %d\r\n%s\r\n%s", method, ctxt->path, ctxt->hostname, len, headers, input);#else sprintf(buf, "%s %s HTTP/1.0\r\nHost: %s\r\nContent-Length: %d\r\n%s\r\n%s", method, ctxt->path, ctxt->hostname, len, headers, input);#endif } else {#ifdef HAVE_SNPRINTF snprintf(buf, sizeof(buf),"%s %s HTTP/1.0\r\nHost: %s\r\nContent-Type: %s\r\nContent-Length: %d\r\n%s\r\n%s", method, ctxt->path, ctxt->hostname, *contentType, len, headers, input);#else sprintf(buf,"%s %s HTTP/1.0\r\nHost: %s\r\nContent-Type: %s\r\nContent-Length: %d\r\n%s\r\n%s", method, ctxt->path, ctxt->hostname, *contentType, len, headers, input);#endif } } }#ifdef DEBUG_HTTP printf("-> %s", buf);#endif ctxt->outptr = ctxt->out = xmlMemStrdup(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; if (p != NULL) xmlFree(p); break; } xmlNanoHTTPScanAnswer(ctxt, p);#ifdef DEBUG_HTTP if (p != NULL) printf("<- %s\n", p);#endif if (p != NULL) xmlFree(p); } if ((ctxt->location != NULL) && (ctxt->returnValue >= 300) && (ctxt->returnValue < 400)) {#ifdef DEBUG_HTTP printf("\nRedirect to: %s\n", ctxt->location);#endif while (xmlNanoHTTPRecv(ctxt)) ; if (nbRedirects < XML_NANO_HTTP_MAX_REDIR) { nbRedirects++; redirURL = xmlMemStrdup(ctxt->location); xmlNanoHTTPFreeCtxt(ctxt); goto retry; } xmlNanoHTTPFreeCtxt(ctxt);#ifdef DEBUG_HTTP printf("Too many redirrects, aborting ...\n");#endif return(NULL); } if ((contentType != NULL) && (ctxt->contentType != NULL)) *contentType = xmlMemStrdup(ctxt->contentType); else if (contentType != NULL) *contentType = NULL;#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);}/** * 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 */intxmlNanoHTTPFetch(const char *URL, const char *filename, char **contentType) { void *ctxt; char buf[4096]; int fd; int len; ctxt = xmlNanoHTTPOpen(URL, contentType); if (ctxt == NULL) return(-1); if (!strcmp(filename, "-")) fd = 0; else { fd = open(filename, O_CREAT | O_WRONLY, 00644); if (fd < 0) { xmlNanoHTTPClose(ctxt); if ((contentType != NULL) && (*contentType != NULL)) { xmlFree(*contentType); *contentType = NULL; } return(-1); } } while ((len = xmlNanoHTTPRead(ctxt, buf, sizeof(buf))) > 0) { write(fd, buf, len); } xmlNanoHTTPClose(ctxt); close(fd); return(0);}/** * xmlNanoHTTPSave: * @ctxt: the HTTP context * @filename: the filename where the content should be saved * * This function saves the output of the HTTP transaction to a file * It closes and free the context at the end * * Returns -1 in case of failure, 0 incase of success. */intxmlNanoHTTPSave(void *ctxt, const char *filename) { char buf[4096]; int fd; int len; if (ctxt == NULL) return(-1); if (!strcmp(filename, "-")) fd = 0; else { fd = open(filename, O_CREAT | O_WRONLY); if (fd < 0) { xmlNanoHTTPClose(ctxt); return(-1); } } while ((len = xmlNanoHTTPRead(ctxt, buf, sizeof(buf))) > 0) { write(fd, buf, len); } xmlNanoHTTPClose(ctxt); return(0);}/** * xmlNanoHTTPReturnCode: * @ctx: the HTTP context * * Returns the HTTP return code for the request. */intxmlNanoHTTPReturnCode(void *ctx) { xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr) ctx; if (ctxt == NULL) return(-1); return(ctxt->returnValue);}#ifdef STANDALONEint main(int argc, char **argv) { char *contentType = NULL; if (argv[1] != NULL) { if (argv[2] != NULL) xmlNanoHTTPFetch(argv[1], argv[2], &contentType); else xmlNanoHTTPFetch(argv[1], "-", &contentType); if (contentType != NULL) xmlFree(contentType); } else { printf("%s: minimal HTTP GET implementation\n", argv[0]); printf("\tusage %s [ URL [ filename ] ]\n", argv[0]); } xmlNanoHTTPCleanup(); xmlMemoryDump(); return(0);}#endif /* STANDALONE */#else /* !LIBXML_HTTP_ENABLED */#ifdef STANDALONE#include <stdio.h>int main(int argc, char **argv) { printf("%s : HTTP support not compiled in\n", argv[0]); return(0);}#endif /* STANDALONE */#endif /* LIBXML_HTTP_ENABLED */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -