1/* 2 * Generic HTTP routines 3 * 4 * Copyright (C) 2010, Broadcom Corporation. All Rights Reserved. 5 * 6 * Permission to use, copy, modify, and/or distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 13 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 15 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 16 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 * 18 * $Id: http.c,v 1.11 2005/08/09 22:18:32 Exp $ 19 */ 20 21#include <stdio.h> 22#include <stdlib.h> 23#include <limits.h> 24#include <ctype.h> 25#include <string.h> 26#include <signal.h> 27#include <time.h> 28#include <unistd.h> 29#include <errno.h> 30#include <sys/socket.h> 31#include <netinet/in.h> 32#include <arpa/inet.h> 33 34#include <shutils.h> 35 36static char * 37base64enc(const char *p, char *buf, int len) 38{ 39 char al[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" 40 "0123456789+/"; 41 char *s = buf; 42 43 while (*p) { 44 if (s >= buf+len-4) 45 break; 46 *(s++) = al[(*p >> 2) & 0x3F]; 47 *(s++) = al[((*p << 4) & 0x30) | ((*(p+1) >> 4) & 0x0F)]; 48 *s = *(s+1) = '='; 49 *(s+2) = 0; 50 if (! *(++p)) break; 51 *(s++) = al[((*p << 2) & 0x3C) | ((*(p+1) >> 6) & 0x03)]; 52 if (! *(++p)) break; 53 *(s++) = al[*(p++) & 0x3F]; 54 } 55 56 return buf; 57} 58 59enum { 60 METHOD_GET, 61 METHOD_POST 62}; 63 64static int 65wget(int method, const char *server, char *buf, size_t count, off_t offset) 66{ 67 char url[PATH_MAX] = { 0 }, *s; 68 char *host = url, *path = "", auth[128] = { 0 }, line[512]; 69 unsigned short port = 80; 70 int fd; 71 FILE *fp; 72 struct sockaddr_in sin; 73 int chunked = 0, len = 0; 74 75 if (server == NULL || !strcmp(server, "")) { 76 dprintf("wget: null server input\n"); 77 return (0); 78 } 79 80 strncpy(url, server, sizeof(url)); 81 82 /* Parse URL */ 83 if (!strncmp(url, "http://", 7)) { 84 port = 80; 85 host = url + 7; 86 } 87 if ((s = strchr(host, '/'))) { 88 *s++ = '\0'; 89 path = s; 90 } 91 if ((s = strchr(host, '@'))) { 92 *s++ = '\0'; 93 base64enc(host, auth, sizeof(auth)); 94 host = s; 95 } 96 if ((s = strchr(host, ':'))) { 97 *s++ = '\0'; 98 port = atoi(s); 99 } 100 101 /* Open socket */ 102 if (!inet_aton(host, &sin.sin_addr)) 103 return 0; 104 sin.sin_family = AF_INET; 105 sin.sin_port = htons(port); 106 107 dprintf("Connecting to %s:%u...\n", host, port); 108 if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0 || 109 connect(fd, (struct sockaddr *) &sin, sizeof(sin)) < 0 || 110 !(fp = fdopen(fd, "r+"))) { 111 perror(host); 112 if (fd >= 0) 113 close(fd); 114 return 0; 115 } 116 dprintf("connected!\n"); 117 118 /* Send HTTP request */ 119 fprintf(fp, "%s /%s HTTP/1.1\r\n", method == METHOD_POST ? "POST" : "GET", path); 120 fprintf(fp, "Host: %s\r\n", host); 121 fprintf(fp, "User-Agent: wget\r\n"); 122 if (strlen(auth)) 123 fprintf(fp, "Authorization: Basic %s\r\n", auth); 124 if (offset) 125 fprintf(fp, "Range: bytes=%ld-\r\n", offset); 126 if (method == METHOD_POST) { 127 fprintf(fp, "Content-Type: application/x-www-form-urlencoded\r\n"); 128 fprintf(fp, "Content-Length: %d\r\n\r\n", (int) strlen(buf)); 129 fputs(buf, fp); 130 } else 131 fprintf(fp, "Connection: close\r\n\r\n"); 132 133 /* Check HTTP response */ 134 dprintf("HTTP request sent, awaiting response...\n"); 135 if (fgets(line, sizeof(line), fp)) { 136 dprintf("%s", line); 137 for (s = line; *s && !isspace((int)*s); s++); 138 for (; isspace((int)*s); s++); 139 switch (atoi(s)) { 140 case 200: if (offset) goto done; else break; 141 case 206: if (offset) break; else goto done; 142 default: goto done; 143 } 144 } 145 146 /* Parse headers */ 147 while (fgets(line, sizeof(line), fp)) { 148 dprintf("%s", line); 149 for (s = line; *s == '\r'; s++); 150 if (*s == '\n') 151 break; 152 if (!strncasecmp(s, "Content-Length:", 15)) { 153 for (s += 15; isblank(*s); s++); 154 chomp(s); 155 len = atoi(s); 156 } 157 else if (!strncasecmp(s, "Transfer-Encoding:", 18)) { 158 for (s += 18; isblank(*s); s++); 159 chomp(s); 160 if (!strncasecmp(s, "chunked", 7)) 161 chunked = 1; 162 } 163 } 164 165 if (chunked && fgets(line, sizeof(line), fp)) 166 len = strtol(line, NULL, 16); 167 168 len = (len > count) ? count : len; 169 len = fread(buf, 1, len, fp); 170 171done: 172 /* Close socket */ 173 fflush(fp); 174 fclose(fp); 175 return len; 176} 177 178int 179http_get(const char *server, char *buf, size_t count, off_t offset) 180{ 181 return wget(METHOD_GET, server, buf, count, offset); 182} 183 184int 185http_post(const char *server, char *buf, size_t count) 186{ 187 /* No continuation generally possible with POST */ 188 return wget(METHOD_POST, server, buf, count, 0); 189} 190