Annotation of XML/nanohttp.c, revision 1.1

1.1     ! daniel      1: /*
        !             2:  * nanohttp.c: minimalist HTTP implementation to fetch external subsets.
        !             3:  *
        !             4:  * See Copyright for the status of this software.
        !             5:  *
        !             6:  * Daniel.Veillard@w3.org
        !             7:  */
        !             8:  
        !             9: #include <stdio.h>
        !            10: #include <string.h>
        !            11: #include <stdlib.h>
        !            12: #include <unistd.h>
        !            13: #include <sys/socket.h>
        !            14: #include <netinet/in.h>
        !            15: #include <arpa/inet.h>
        !            16: #include <netdb.h>
        !            17: #include <fcntl.h> 
        !            18: #include <errno.h>
        !            19: #include <sys/time.h>
        !            20: #include <sys/select.h>
        !            21: 
        !            22: #define XML_NANO_HTTP_MAX_REDIR        10
        !            23: 
        !            24: #define XML_NANO_HTTP_CHUNK    4096
        !            25: 
        !            26: #define XML_NANO_HTTP_CLOSED   0
        !            27: #define XML_NANO_HTTP_WRITE    1
        !            28: #define XML_NANO_HTTP_READ     2
        !            29: #define XML_NANO_HTTP_NONE     4
        !            30: 
        !            31: typedef struct xmlNanoHTTPCtxt {
        !            32:     char *protocol;    /* the protocol name */
        !            33:     char *hostname;    /* the host name */
        !            34:     int port;          /* the port */
        !            35:     char *path;                /* the path within the URL */
        !            36:     int fd;            /* the file descriptor for the socket */
        !            37:     int state;         /* WRITE / READ / CLOSED */
        !            38:     char *out;         /* buffer sent (zero terminated) */
        !            39:     char *outptr;      /* index within the buffer sent */
        !            40:     char *in;          /* the receiving buffer */
        !            41:     char *content;     /* the start of the content */
        !            42:     char *inptr;       /* the next byte to read from network */
        !            43:     char *inrptr;      /* the next byte to give back to the client */
        !            44:     int inlen;         /* len of the input buffer */
        !            45:     int last;          /* return code for last operation */
        !            46:     int returnValue;   /* the protocol return value */
        !            47:     char *contentType; /* the MIME type for the input */
        !            48:     char *location;    /* the new URL in case of redirect */
        !            49: } xmlNanoHTTPCtxt, *xmlNanoHTTPCtxtPtr;
        !            50: 
        !            51: static void xmlNanoHTTPScanURL(xmlNanoHTTPCtxtPtr ctxt, const char *URL) {
        !            52:     const char *cur = URL;
        !            53:     char buf[4096];
        !            54:     int index = 0;
        !            55:     int port = 0;
        !            56: 
        !            57:     if (ctxt->protocol != NULL) { 
        !            58:         free(ctxt->protocol);
        !            59:        ctxt->protocol = NULL;
        !            60:     }
        !            61:     if (ctxt->hostname != NULL) { 
        !            62:         free(ctxt->hostname);
        !            63:        ctxt->hostname = NULL;
        !            64:     }
        !            65:     if (ctxt->path != NULL) { 
        !            66:         free(ctxt->path);
        !            67:        ctxt->path = NULL;
        !            68:     }
        !            69:     buf[index] = 0;
        !            70:     while (*cur != 0) {
        !            71:         if ((cur[0] == ':') && (cur[1] == '/') && (cur[2] == '/')) {
        !            72:            buf[index] = 0;
        !            73:            ctxt->protocol = strdup(buf);
        !            74:            index = 0;
        !            75:             cur += 3;
        !            76:            break;
        !            77:        }
        !            78:        buf[index++] = *cur++;
        !            79:     }
        !            80:     if (*cur == 0) return;
        !            81: 
        !            82:     buf[index] = 0;
        !            83:     while (1) {
        !            84:         if (cur[0] == ':') {
        !            85:            buf[index] = 0;
        !            86:            ctxt->hostname = strdup(buf);
        !            87:            index = 0;
        !            88:            cur += 1;
        !            89:            while ((*cur >= '0') && (*cur <= '9')) {
        !            90:                port *= 10;
        !            91:                port += *cur - '0';
        !            92:                cur++;
        !            93:            }
        !            94:            if (port != 0) ctxt->port = port;
        !            95:            while ((cur[0] != '/') && (*cur != 0)) 
        !            96:                cur++;
        !            97:            break;
        !            98:        }
        !            99:         if ((*cur == '/') || (*cur == 0)) {
        !           100:            buf[index] = 0;
        !           101:            ctxt->hostname = strdup(buf);
        !           102:            index = 0;
        !           103:            break;
        !           104:        }
        !           105:        buf[index++] = *cur++;
        !           106:     }
        !           107:     if (*cur == 0) 
        !           108:         ctxt->path = strdup("/");
        !           109:     else
        !           110:        ctxt->path = strdup(cur);
        !           111: }
        !           112: 
        !           113: static xmlNanoHTTPCtxtPtr xmlNanoHTTPNewCtxt(const char *URL) {
        !           114:     xmlNanoHTTPCtxtPtr ret;
        !           115: 
        !           116:     ret = (xmlNanoHTTPCtxtPtr) malloc(sizeof(xmlNanoHTTPCtxt));
        !           117:     if (ret == NULL) return(NULL);
        !           118: 
        !           119:     memset(ret, 0, sizeof(xmlNanoHTTPCtxt));
        !           120:     ret->port = 80;
        !           121:     ret->returnValue = 0;
        !           122: 
        !           123:     xmlNanoHTTPScanURL(ret, URL);
        !           124: 
        !           125:     return(ret);
        !           126: }
        !           127: 
        !           128: static void xmlNanoHTTPFreeCtxt(xmlNanoHTTPCtxtPtr ctxt) {
        !           129:     if (ctxt->hostname != NULL) free(ctxt->hostname);
        !           130:     if (ctxt->protocol != NULL) free(ctxt->protocol);
        !           131:     if (ctxt->path != NULL) free(ctxt->path);
        !           132:     if (ctxt->out != NULL) free(ctxt->out);
        !           133:     if (ctxt->in != NULL) free(ctxt->in);
        !           134:     if (ctxt->contentType != NULL) free(ctxt->contentType);
        !           135:     if (ctxt->location != NULL) free(ctxt->location);
        !           136:     ctxt->state = XML_NANO_HTTP_NONE;
        !           137:     if (ctxt->fd >= 0) close(ctxt->fd);
        !           138:     ctxt->fd = -1;
        !           139:     free(ctxt);
        !           140: }
        !           141: 
        !           142: static void xmlNanoHTTPSend(xmlNanoHTTPCtxtPtr ctxt) {
        !           143:     if (ctxt->state & XML_NANO_HTTP_WRITE)
        !           144:        ctxt->last = write(ctxt->fd, ctxt->outptr, strlen(ctxt->outptr));
        !           145: }
        !           146: 
        !           147: static int xmlNanoHTTPRecv(xmlNanoHTTPCtxtPtr ctxt) {
        !           148:     fd_set rfd;
        !           149:     struct timeval tv;
        !           150: 
        !           151: 
        !           152:     while (ctxt->state & XML_NANO_HTTP_READ) {
        !           153:        if (ctxt->in == NULL) {
        !           154:            ctxt->in = (char *) malloc(65000 * sizeof(char));
        !           155:            if (ctxt->in == NULL) {
        !           156:                ctxt->last = -1;
        !           157:                return(-1);
        !           158:            }
        !           159:            ctxt->inlen = 65000;
        !           160:            ctxt->inptr = ctxt->content = ctxt->inrptr = ctxt->in;
        !           161:        }
        !           162:        if (ctxt->inrptr > ctxt->in + XML_NANO_HTTP_CHUNK) {
        !           163:            int delta = ctxt->inrptr - ctxt->in;
        !           164:            int len = ctxt->inptr - ctxt->inrptr;
        !           165:            
        !           166:            memmove(ctxt->in, ctxt->inrptr, len);
        !           167:            ctxt->inrptr -= delta;
        !           168:            ctxt->content -= delta;
        !           169:            ctxt->inptr -= delta;
        !           170:        }
        !           171:         if ((ctxt->in + ctxt->inlen) < (ctxt->inptr + XML_NANO_HTTP_CHUNK)) {
        !           172:            int d_inptr = ctxt->inptr - ctxt->in;
        !           173:            int d_content = ctxt->content - ctxt->in;
        !           174:            int d_inrptr = ctxt->inrptr - ctxt->in;
        !           175: 
        !           176:            ctxt->inlen *= 2;
        !           177:             ctxt->in = (char *) realloc(ctxt->in, ctxt->inlen);
        !           178:            if (ctxt->in == NULL) {
        !           179:                ctxt->last = -1;
        !           180:                return(-1);
        !           181:            }
        !           182:             ctxt->inptr = ctxt->in + d_inptr;
        !           183:             ctxt->content = ctxt->in + d_content;
        !           184:             ctxt->inrptr = ctxt->in + d_inrptr;
        !           185:        }
        !           186:        ctxt->last = read(ctxt->fd, ctxt->inptr, XML_NANO_HTTP_CHUNK);
        !           187:        if (ctxt->last > 0) {
        !           188:            ctxt->inptr += ctxt->last;
        !           189:            return(ctxt->last);
        !           190:        }
        !           191:        if (ctxt->last == 0) {
        !           192:            return(0);
        !           193:        }
        !           194: #ifdef EWOULDBLOCK
        !           195:        if ((ctxt->last == -1) && (errno != EWOULDBLOCK)) {
        !           196:            return 0;
        !           197:        }
        !           198: #endif
        !           199:        tv.tv_sec=10;
        !           200:        tv.tv_usec=0;
        !           201:        FD_ZERO(&rfd);
        !           202:        FD_SET(ctxt->fd, &rfd);
        !           203:        
        !           204:        if(select(ctxt->fd+1, &rfd, NULL, NULL, &tv)<1)
        !           205:                return 0;
        !           206:     }
        !           207:     return(0);
        !           208: }
        !           209: 
        !           210: char *xmlNanoHTTPReadLine(xmlNanoHTTPCtxtPtr ctxt) {
        !           211:     static char buf[4096];
        !           212:     char *bp=buf;
        !           213:     
        !           214:     while(bp - buf < 4095) {
        !           215:        if(ctxt->inrptr == ctxt->inptr) {
        !           216:            if (xmlNanoHTTPRecv(ctxt) == 0) {
        !           217:                if (bp == buf)
        !           218:                    return NULL;
        !           219:                else
        !           220:                    *bp = 0;
        !           221:                return buf;
        !           222:            }
        !           223:        }
        !           224:        *bp = *ctxt->inrptr++;
        !           225:        if(*bp == '\n') {
        !           226:            *bp = 0;
        !           227:            return buf;
        !           228:        }
        !           229:        if(*bp != '\r')
        !           230:            bp++;
        !           231:     }
        !           232:     buf[4095] = 0;
        !           233:     return(buf);
        !           234: }
        !           235: 
        !           236:        
        !           237: static void xmlNanoHTTPScanAnswer(xmlNanoHTTPCtxtPtr ctxt, const char *line) {
        !           238:     const char *cur = line;
        !           239: 
        !           240:     if (line == NULL) return;
        !           241: 
        !           242:     if (!strncmp(line, "HTTP/", 5)) {
        !           243:         int version = 0;
        !           244:        int ret = 0;
        !           245: 
        !           246:        cur += 5;
        !           247:        while ((*cur >= '0') && (*cur <= '9')) {
        !           248:            version *= 10;
        !           249:            version += *cur - '0';
        !           250:            cur++;
        !           251:        }
        !           252:        if (*cur == '.') {
        !           253:            cur++;
        !           254:            if ((*cur >= '0') && (*cur <= '9')) {
        !           255:                version *= 10;
        !           256:                version += *cur - '0';
        !           257:                cur++;
        !           258:            }
        !           259:            while ((*cur >= '0') && (*cur <= '9'))
        !           260:                cur++;
        !           261:        } else
        !           262:            version *= 10;
        !           263:        if ((*cur != ' ') && (*cur != '\t')) return;
        !           264:        while ((*cur == ' ') || (*cur == '\t')) cur++;
        !           265:        if ((*cur < '0') || (*cur > '9')) return;
        !           266:        while ((*cur >= '0') && (*cur <= '9')) {
        !           267:            ret *= 10;
        !           268:            ret += *cur - '0';
        !           269:            cur++;
        !           270:        }
        !           271:        if ((*cur != 0) && (*cur != ' ') && (*cur != '\t')) return;
        !           272:        ctxt->returnValue = ret;
        !           273:     } else if (!strncmp(line, "Content-Type:", 13)) {
        !           274:         cur += 13;
        !           275:        while ((*cur == ' ') || (*cur == '\t')) cur++;
        !           276:        if (ctxt->contentType != NULL)
        !           277:            free(ctxt->contentType);
        !           278:        ctxt->contentType = strdup(cur);
        !           279:     } else if (!strncmp(line, "ContentType:", 12)) {
        !           280:         cur += 12;
        !           281:        if (ctxt->contentType != NULL) return;
        !           282:        while ((*cur == ' ') || (*cur == '\t')) cur++;
        !           283:        ctxt->contentType = strdup(cur);
        !           284:     } else if (!strncmp(line, "content-type:", 13)) {
        !           285:         cur += 13;
        !           286:        if (ctxt->contentType != NULL) return;
        !           287:        while ((*cur == ' ') || (*cur == '\t')) cur++;
        !           288:        ctxt->contentType = strdup(cur);
        !           289:     } else if (!strncmp(line, "contenttype:", 12)) {
        !           290:         cur += 12;
        !           291:        if (ctxt->contentType != NULL) return;
        !           292:        while ((*cur == ' ') || (*cur == '\t')) cur++;
        !           293:        ctxt->contentType = strdup(cur);
        !           294:     } else if (!strncmp(line, "Location:", 9)) {
        !           295:         cur += 9;
        !           296:        while ((*cur == ' ') || (*cur == '\t')) cur++;
        !           297:        if (ctxt->location != NULL)
        !           298:            free(ctxt->location);
        !           299:        ctxt->location = strdup(cur);
        !           300:     } else if (!strncmp(line, "location:", 9)) {
        !           301:         cur += 9;
        !           302:        if (ctxt->location != NULL) return;
        !           303:        while ((*cur == ' ') || (*cur == '\t')) cur++;
        !           304:        ctxt->location = strdup(cur);
        !           305:     }
        !           306: }
        !           307: 
        !           308: static int xmlNanoHTTPConnectAttempt(struct in_addr ia, int port)
        !           309: {
        !           310:     int s=socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
        !           311:     struct sockaddr_in sin;
        !           312:     fd_set wfd;
        !           313:     struct timeval tv;
        !           314:     
        !           315:     if(s==-1) {
        !           316:        perror("socket");
        !           317:        return(-1);
        !           318:     }
        !           319:     
        !           320:     if(fcntl(s, F_SETFL, FNDELAY)==-1) {
        !           321:        perror("nonblocking");
        !           322:        close(s);
        !           323:        return(-1);
        !           324:     }
        !           325: 
        !           326:     sin.sin_family = AF_INET;  
        !           327:     sin.sin_addr   = ia;
        !           328:     sin.sin_port   = htons(port);
        !           329:     
        !           330:     if((connect(s, (struct sockaddr *)&sin, sizeof(sin))==-1) &&
        !           331:        (errno != EINPROGRESS)) {
        !           332:        perror("connect");
        !           333:        close(s);
        !           334:        return(-1);
        !           335:     }  
        !           336:     
        !           337:     tv.tv_sec = 60;            /* We use 60 second timeouts for now */
        !           338:     tv.tv_usec = 0;
        !           339:     
        !           340:     FD_ZERO(&wfd);
        !           341:     FD_SET(s, &wfd);
        !           342:     
        !           343:     switch(select(s+1, NULL, &wfd, NULL, &tv))
        !           344:     {
        !           345:        case 0:
        !           346:            /* Time out */
        !           347:            close(s);
        !           348:            return(-1);
        !           349:        case -1:
        !           350:            /* Ermm.. ?? */
        !           351:            perror("select");
        !           352:            close(s);
        !           353:            return(-1);
        !           354:     }
        !           355:     
        !           356:     return s;
        !           357: }
        !           358:  
        !           359: int xmlNanoHTTPConnectHost(const char *host, int port)
        !           360: {
        !           361:     struct hostent *h;
        !           362:     int i;
        !           363:     int s;
        !           364:     
        !           365:     h=gethostbyname(host);
        !           366:     if(h==NULL)
        !           367:     {
        !           368:        fprintf(stderr,"unable to resolve '%s'.\n", host);
        !           369:        return(-1);
        !           370:     }
        !           371:     
        !           372:     
        !           373:     for(i=0; h->h_addr_list[i]; i++)
        !           374:     {
        !           375:        struct in_addr ia;
        !           376:        memcpy(&ia, h->h_addr_list[i],4);
        !           377:        s = xmlNanoHTTPConnectAttempt(ia, port);
        !           378:        if(s != -1)
        !           379:                return s;
        !           380:     }
        !           381:     fprintf(stderr, "unable to connect to '%s'.\n", host);
        !           382:     return(-1);
        !           383: }
        !           384: 
        !           385: int xmlNanoHTTPOldFetch(const char *URL, const char *filename,
        !           386:                      char **contentType) {
        !           387:     xmlNanoHTTPCtxtPtr ctxt;
        !           388:     char buf[4096];
        !           389:     int ret;
        !           390:     int fd;
        !           391:     char *p;
        !           392:     int head;
        !           393:     int nbRedirects = 0;
        !           394:     char *redirURL = NULL;
        !           395:     
        !           396: retry:
        !           397:     if (redirURL == NULL)
        !           398:        ctxt = xmlNanoHTTPNewCtxt(URL);
        !           399:     else
        !           400:        ctxt = xmlNanoHTTPNewCtxt(redirURL);
        !           401: 
        !           402:     if ((ctxt->protocol == NULL) || (strcmp(ctxt->protocol, "http"))) {
        !           403:         xmlNanoHTTPFreeCtxt(ctxt);
        !           404:        if (redirURL != NULL) free(redirURL);
        !           405:         return(-1);
        !           406:     }
        !           407:     if (ctxt->hostname == NULL) {
        !           408:         xmlNanoHTTPFreeCtxt(ctxt);
        !           409:        if (redirURL != NULL) free(redirURL);
        !           410:         return(-1);
        !           411:     }
        !           412:     ret = xmlNanoHTTPConnectHost(ctxt->hostname, ctxt->port);
        !           413:     if (ret < 0) {
        !           414:         xmlNanoHTTPFreeCtxt(ctxt);
        !           415:        if (redirURL != NULL) free(redirURL);
        !           416:         return(-1);
        !           417:     }
        !           418:     ctxt->fd = ret;
        !           419:     snprintf(buf, sizeof(buf),"GET %s HTTP/1.0\r\nhost: %s\r\n\r\n",
        !           420:             ctxt->path, ctxt->hostname);
        !           421:     ctxt->outptr = ctxt->out = strdup(buf);
        !           422:     ctxt->state = XML_NANO_HTTP_WRITE;
        !           423:     xmlNanoHTTPSend(ctxt);
        !           424:     ctxt->state = XML_NANO_HTTP_READ;
        !           425:     head = 1;
        !           426: 
        !           427:     while ((p = xmlNanoHTTPReadLine(ctxt)) != NULL) {
        !           428:         if (head && (*p == 0)) {
        !           429:            head = 0;
        !           430:            ctxt->content = ctxt->inrptr;
        !           431:            break;
        !           432:        }
        !           433:        xmlNanoHTTPScanAnswer(ctxt, p);
        !           434: if (p != NULL) printf("%s\n", p);
        !           435:     }
        !           436:     while (xmlNanoHTTPRecv(ctxt)) ;
        !           437: 
        !           438:     if (!strcmp(filename, "-")) 
        !           439:         fd = 0;
        !           440:     else {
        !           441:         fd = open(filename, O_CREAT | O_WRONLY);
        !           442:        if (fd < 0) {
        !           443:            xmlNanoHTTPFreeCtxt(ctxt);
        !           444:            if (redirURL != NULL) free(redirURL);
        !           445:            return(-1);
        !           446:        }
        !           447:     }
        !           448: 
        !           449: printf("Code %d, content-type '%s'\n\n",
        !           450:        ctxt->returnValue, ctxt->contentType);
        !           451:     if ((ctxt->location != NULL) && (ctxt->returnValue >= 300) &&
        !           452:         (ctxt->returnValue < 400)) {
        !           453: printf("Redirect to: %s\n", ctxt->location);
        !           454:         if (nbRedirects < XML_NANO_HTTP_MAX_REDIR) {
        !           455:            nbRedirects++;
        !           456:            if (redirURL != NULL) free(redirURL);
        !           457:            redirURL = strdup(ctxt->location);
        !           458:            xmlNanoHTTPFreeCtxt(ctxt);
        !           459:            goto retry;
        !           460:        }
        !           461:     }
        !           462: 
        !           463:     write(fd, ctxt->content, ctxt->inptr - ctxt->content);
        !           464:     xmlNanoHTTPFreeCtxt(ctxt);
        !           465:     if (redirURL != NULL) free(redirURL);
        !           466:     return(0);
        !           467: }
        !           468: 
        !           469: void *
        !           470: xmlNanoHTTPOpen(const char *URL, char **contentType) {
        !           471:     xmlNanoHTTPCtxtPtr ctxt;
        !           472:     char buf[4096];
        !           473:     int ret;
        !           474:     char *p;
        !           475:     int head;
        !           476:     int nbRedirects = 0;
        !           477:     char *redirURL = NULL;
        !           478:     
        !           479: retry:
        !           480:     if (redirURL == NULL)
        !           481:        ctxt = xmlNanoHTTPNewCtxt(URL);
        !           482:     else {
        !           483:        ctxt = xmlNanoHTTPNewCtxt(redirURL);
        !           484:        free(redirURL);
        !           485:        redirURL = NULL;
        !           486:     }
        !           487: 
        !           488:     if ((ctxt->protocol == NULL) || (strcmp(ctxt->protocol, "http"))) {
        !           489:         xmlNanoHTTPFreeCtxt(ctxt);
        !           490:        if (redirURL != NULL) free(redirURL);
        !           491:         return(NULL);
        !           492:     }
        !           493:     if (ctxt->hostname == NULL) {
        !           494:         xmlNanoHTTPFreeCtxt(ctxt);
        !           495:         return(NULL);
        !           496:     }
        !           497:     ret = xmlNanoHTTPConnectHost(ctxt->hostname, ctxt->port);
        !           498:     if (ret < 0) {
        !           499:         xmlNanoHTTPFreeCtxt(ctxt);
        !           500:         return(NULL);
        !           501:     }
        !           502:     ctxt->fd = ret;
        !           503:     snprintf(buf, sizeof(buf),"GET %s HTTP/1.0\r\nhost: %s\r\n\r\n",
        !           504:             ctxt->path, ctxt->hostname);
        !           505:     ctxt->outptr = ctxt->out = strdup(buf);
        !           506:     ctxt->state = XML_NANO_HTTP_WRITE;
        !           507:     xmlNanoHTTPSend(ctxt);
        !           508:     ctxt->state = XML_NANO_HTTP_READ;
        !           509:     head = 1;
        !           510: 
        !           511:     while ((p = xmlNanoHTTPReadLine(ctxt)) != NULL) {
        !           512:         if (head && (*p == 0)) {
        !           513:            head = 0;
        !           514:            ctxt->content = ctxt->inrptr;
        !           515:            break;
        !           516:        }
        !           517:        xmlNanoHTTPScanAnswer(ctxt, p);
        !           518: 
        !           519: if (p != NULL) printf("%s\n", p);
        !           520:     }
        !           521: 
        !           522:     if ((ctxt->location != NULL) && (ctxt->returnValue >= 300) &&
        !           523:         (ctxt->returnValue < 400)) {
        !           524: printf("Redirect to: %s\n", ctxt->location);
        !           525:        while (xmlNanoHTTPRecv(ctxt)) ;
        !           526:         if (nbRedirects < XML_NANO_HTTP_MAX_REDIR) {
        !           527:            nbRedirects++;
        !           528:            redirURL = strdup(ctxt->location);
        !           529:            xmlNanoHTTPFreeCtxt(ctxt);
        !           530:            goto retry;
        !           531:        }
        !           532:        xmlNanoHTTPFreeCtxt(ctxt);
        !           533:        return(NULL);
        !           534: 
        !           535:     }
        !           536: 
        !           537: printf("Code %d, content-type '%s'\n\n",
        !           538:        ctxt->returnValue, ctxt->contentType);
        !           539: 
        !           540:     return((void *) ctxt);
        !           541: }
        !           542: 
        !           543: int
        !           544: xmlNanoHTTPRead(void *ctx, void *dest, int len) {
        !           545:     xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr) ctx;
        !           546: 
        !           547:     if (ctx == NULL) return(-1);
        !           548:     if (dest == NULL) return(-1);
        !           549:     if (len <= 0) return(0);
        !           550: 
        !           551:     while (ctxt->inptr - ctxt->inrptr < len) {
        !           552:         if (xmlNanoHTTPRecv(ctxt) == 0) break;
        !           553:     }
        !           554:     if (ctxt->inptr - ctxt->inrptr < len)
        !           555:         len = ctxt->inptr - ctxt->inrptr;
        !           556:     memcpy(dest, ctxt->inrptr, len);
        !           557:     ctxt->inrptr += len;
        !           558:     return(len);
        !           559: }
        !           560: 
        !           561: void
        !           562: xmlNanoHTTPClose(void *ctx) {
        !           563:     xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr) ctx;
        !           564: 
        !           565:     if (ctx == NULL) return;
        !           566: 
        !           567:     xmlNanoHTTPFreeCtxt(ctxt);
        !           568: }
        !           569: 
        !           570: int xmlNanoHTTPFetch(const char *URL, const char *filename,
        !           571:                      char **contentType) {
        !           572:     void *ctxt;
        !           573:     char buf[4096];
        !           574:     int fd;
        !           575:     int len;
        !           576:     
        !           577:     ctxt = xmlNanoHTTPOpen(URL, contentType);
        !           578:     if (ctxt == NULL) return(-1);
        !           579: 
        !           580:     if (!strcmp(filename, "-")) 
        !           581:         fd = 0;
        !           582:     else {
        !           583:         fd = open(filename, O_CREAT | O_WRONLY);
        !           584:        if (fd < 0) {
        !           585:            xmlNanoHTTPClose(ctxt);
        !           586:            return(-1);
        !           587:        }
        !           588:     }
        !           589: 
        !           590:     while ((len = xmlNanoHTTPRead(ctxt, buf, sizeof(buf))) > 0) {
        !           591:        write(fd, buf, len);
        !           592:     }
        !           593: 
        !           594:     xmlNanoHTTPClose(ctxt);
        !           595:     return(0);
        !           596: }
        !           597: 
        !           598: #ifdef STANDALONE
        !           599: int main(int argc, char **argv) {
        !           600:     char *contentType = NULL;
        !           601: 
        !           602:     if (argv[1] != NULL) {
        !           603:        if (argv[2] != NULL) 
        !           604:            xmlNanoHTTPFetch(argv[1], argv[2], &contentType);
        !           605:         else
        !           606:            xmlNanoHTTPFetch(argv[1], "-", &contentType);
        !           607:     } else {
        !           608:         printf("%s: minimal HTTP GET implementation\n", argv[0]);
        !           609:         printf("\tusage %s [ URL [ filename ] ]\n", argv[0]);
        !           610:     }
        !           611:     return(0);
        !           612: }
        !           613: #endif /* STANDALONE */

Webmaster