1/* 2 * This program is free software; you can redistribute it and/or 3 * modify it under the terms of the GNU General Public License as 4 * published by the Free Software Foundation; either version 2 of 5 * the License, or (at your option) any later version. 6 * 7 * This program is distributed in the hope that it will be useful, 8 * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 * GNU General Public License for more details. 11 * 12 * You should have received a copy of the GNU General Public License 13 * along with this program; if not, write to the Free Software 14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 15 * MA 02111-1307 USA 16 */ 17/* 18 * Generic HTTP routines 19 * 20 * Copyright 2001, ASUSTeK Inc. 21 * All Rights Reserved. 22 * 23 * This is UNPUBLISHED PROPRIETARY SOURCE CODE of ASUSTeK Inc.; 24 * the contents of this file may not be disclosed to third parties, copied or 25 * duplicated in any form, in whole or in part, without the prior written 26 * permission of ASUSTeK Inc.. 27 * 28 */ 29 30#include <stdio.h> 31#include <stdlib.h> 32#include <limits.h> 33#include <ctype.h> 34#include <string.h> 35#include <signal.h> 36#include <time.h> 37#include <unistd.h> 38#include <errno.h> 39#include <sys/socket.h> 40#include <netinet/in.h> 41#include <arpa/inet.h> 42 43#include <shutils.h> 44 45static char * 46base64enc(const char *p, char *buf, int len) 47{ 48 char al[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" 49 "0123456789+/"; 50 char *s = buf; 51 52 while (*p) { 53 if (s >= buf+len-4) 54 break; 55 *(s++) = al[(*p >> 2) & 0x3F]; 56 *(s++) = al[((*p << 4) & 0x30) | ((*(p+1) >> 4) & 0x0F)]; 57 *s = *(s+1) = '='; 58 *(s+2) = 0; 59 if (! *(++p)) break; 60 *(s++) = al[((*p << 2) & 0x3C) | ((*(p+1) >> 6) & 0x03)]; 61 if (! *(++p)) break; 62 *(s++) = al[*(p++) & 0x3F]; 63 } 64 65 return buf; 66} 67 68enum { 69 METHOD_GET, 70 METHOD_POST 71}; 72 73static int 74wget(int method, const char *server, char *buf, size_t count, off_t offset) 75{ 76 char url[PATH_MAX] = { 0 }, *s; 77 char *host = url, *path = "", auth[128] = { 0 }, line[512]; 78 unsigned short port = 80; 79 int fd; 80 FILE *fp; 81 struct sockaddr_in sin; 82 int chunked = 0, len = 0; 83 84 strncpy(url, server, sizeof(url)); 85 86 /* Parse URL */ 87 if (!strncmp(url, "http://", 7)) { 88 port = 80; 89 host = url + 7; 90 } 91 if ((s = strchr(host, '/'))) { 92 *s++ = '\0'; 93 path = s; 94 } 95 if ((s = strchr(host, '@'))) { 96 *s++ = '\0'; 97 base64enc(host, auth, sizeof(auth)); 98 host = s; 99 } 100 if ((s = strchr(host, ':'))) { 101 *s++ = '\0'; 102 port = atoi(s); 103 } 104 105 /* Open socket */ 106 if (!inet_aton(host, &sin.sin_addr)) 107 return (-(errno = EINVAL)); 108 sin.sin_family = AF_INET; 109 sin.sin_port = htons(port); 110 111 dprintf("Connecting to %s:%u...\n", host, port); 112 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0 || 113 connect(fd, (struct sockaddr *) &sin, sizeof(sin)) < 0 || 114 !(fp = fdopen(fd, "r+"))) { 115 perror(host); 116 if (fd >= 0) 117 close(fd); 118 return -errno; 119 } 120 dprintf("connected!\n"); 121 122 /* Send HTTP request */ 123 fprintf(fp, "%s /%s HTTP/1.1\r\n", method == METHOD_POST ? "POST" : "GET", path); 124 fprintf(fp, "Host: %s\r\n", host); 125 fprintf(fp, "User-Agent: wget\r\n"); 126 if (strlen(auth)) 127 fprintf(fp, "Authorization: Basic %s\r\n", auth); 128 if (offset) 129 fprintf(fp, "Range: bytes=%ld-\r\n", offset); 130 if (method == METHOD_POST) { 131 fprintf(fp, "Content-Type: application/x-www-form-urlencoded\r\n"); 132 fprintf(fp, "Content-Length: %d\r\n\r\n", strlen(buf)); 133 fputs(buf, fp); 134 } else 135 fprintf(fp,"Connection: close\r\n\r\n"); 136 137 /* Check HTTP response */ 138 dprintf("HTTP request sent, awaiting response...\n"); 139 if (fgets(line, sizeof(line), fp)) { 140 dprintf("%s", line); 141 for (s = line; *s && !isspace(*s); s++); 142 for (; isspace(*s); s++); 143 switch (atoi(s)) { 144 case 200: if (offset) goto done; else break; 145 case 206: if (offset) break; else goto done; 146 default: goto done; 147 } 148 } 149 150 /* Parse headers */ 151 while (fgets(line, sizeof(line), fp)) { 152 dprintf("%s", line); 153 for (s = line; *s == '\r'; s++); 154 if (*s == '\n') 155 break; 156 if (!strncasecmp(s, "Content-Length:", 15)) { 157 for (s += 15; isblank(*s); s++); 158 chomp(s); 159 len = atoi(s); 160 } 161 else if (!strncasecmp(s, "Transfer-Encoding:", 18)) { 162 for (s += 18; isblank(*s); s++); 163 chomp(s); 164 if (!strncasecmp(s, "chunked", 7)) 165 chunked = 1; 166 } 167 } 168 169 if (chunked && fgets(line, sizeof(line), fp)) 170 len = strtol(line, NULL, 16); 171 172 len = (len > count) ? count : len; 173 len = fread(buf, 1, len, fp); 174 175 done: 176 /* Close socket */ 177 fflush(fp); 178 fclose(fp); 179 return len; 180} 181 182int 183http_get(const char *server, char *buf, size_t count, off_t offset) 184{ 185 return wget(METHOD_GET, server, buf, count, offset); 186} 187 188int 189http_post(const char *server, char *buf, size_t count) 190{ 191 /* No continuation generally possible with POST */ 192 return wget(METHOD_POST, server, buf, count, 0); 193} 194