C言語でHTTPリクエストしてみた

動くけど、C言語の流儀は無視した作りになってしまった…。
parseURLではsubstringっぽい処理が多い。
C言語では区切りたい所に\0を突っ込んで終わりを示すのが普通らしい。
関数がポインタを返すのもよくないのかも知れない。
 
ソースは大体ここから。
 
C 言語で HTTP クライアントを作ってみよう (1)
http://x68000.q-e-d.net/~68user/net/c-http-1.html
 

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netdb.h>
#include <sys/socket.h>
#include <netinet/in.h>

#define BUF_LEN 256

typedef struct {
	char schema[10];
	char domain[255];
	char path[255];
	int port;
} URL;

URL *parseURL(char *url)
{
	URL *obj;
	char *p;
	char *p_domain;
	char *p_path;
	char *p_end;

	obj = (URL *)malloc(sizeof(URL));
	memset(obj, '\0', sizeof(URL));
	p_end = url + strlen(url);
	p = strstr(url, "://");
	if (p) {
		strncpy(obj->schema, url, p-url);
		p_domain = url+strlen(obj->schema)+3;
		if (p_path = strchr(p_domain, '/')) {
			strncpy(obj->domain, p_domain, p_path-p_domain);
			strncpy(obj->path, p_path, p_end-p_path);
		} else {
			strncpy(obj->domain, p_domain, p_end-p_domain);
			strcpy(obj->path, "/");
		}
		if (p = strchr(obj->domain, ':')) {
			obj->port = atoi(p+1);
			*p = '\0';
		}
		if (0<strlen(obj->domain)) {
			return obj;
		}
	}
	return NULL;
}

int main(int argc, char *argv[])
{
	int s;
	struct hostent *servhost;
	struct in_addr addr;
	struct sockaddr_in server;
	char send_buf[BUF_LEN];
	int i;
	URL *url;

	if (argc<2) {
		printf("usage: %s http://domain/path\n", argv[0]);
		return 1;
	}

	url = parseURL(argv[1]);
	if (url == NULL) {
		printf("Parse error: %s\n", argv[1]);
		return 1;
	}
	servhost = gethostbyname(url->domain);
	if (servhost == NULL) {
		printf("IP変換失敗\n");
		return 1;
	}

	printf("servhost->h_name: %s\n", servhost->h_name);
	for (i=0; servhost->h_aliases[i]; i++) {
		printf("servhost->h_aliases[%u]: %s\n", i, servhost->h_aliases[i]);
	}
	printf("servhost->h_addrtype: %u\n", servhost->h_addrtype);
	printf("servhost->h_length: %u\n", servhost->h_length);
	for (i=0; servhost->h_addr_list[i]; i++) {
		memcpy(&addr, servhost->h_addr_list[i], 4);
		printf("servhost->h_addr_list[%u]: %s\n", i, inet_ntoa(addr));
	}
	printf("\n");

	memset(&server, '\0', sizeof(server));
	server.sin_family = AF_INET;
	memcpy(&server.sin_addr, servhost->h_addr, servhost->h_length);
	server.sin_port = htons(80);

	// ソケット作成
	if ( (s = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
		printf("ソケット作成失敗\n");
		return 1;
	}

	// 接続
	if (connect(s, (struct sockaddr *)&server, sizeof(server)) == -1) {
		printf("接続失敗\n");
		return 1;
	}

	// write
	sprintf(send_buf, "GET %s HTTP/1.1\r\n", url->path);
	write(s, send_buf, strlen(send_buf));

	sprintf(send_buf, "host: %s\r\n", url->domain);
	write(s, send_buf, strlen(send_buf));

	sprintf(send_buf, "\r\n");
	write(s, send_buf, strlen(send_buf));

	// read
	while (1) {
		char buf[BUF_LEN];
		memset(buf, '\0', BUF_LEN);
		int read_size;
		read_size = read(s, buf, BUF_LEN);
		if (0<read_size) {
			write(1, buf, read_size);
		} else {
			break;
		}
	}

	close(s);
	free(url);

	return 0;
}