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