Uživatelské nástroje

Nástroje pro tento web


pitel:ipk:projekt1

Webclient

xkalab00.tar.gz

Vytvoření klientské síťové aplikace v prostředí UNIXu s využitím komunikačního rozhraní BSD sockets.

Vytvořte program (klient) s využitím rozhraní schránek (BSD sockets), který implementuje stahování zadaného objektu a případných vnořených objektů pomocí URL z WWW serveru s využitím HTTP protokolu do souboru uloženého v lokálním souborovém systému.

Vytvořte program v jazyce C/C++, který je přeložitelný na studentském unixovém serveru eva včetně funkčního Makefile souboru (program přeložitelný po zadání příkazu make). Program využívá spojovanou službu (protokol TCP). Jméno přeloženého programu klienta bude webclient. Program předpokládá jeden povinný parametr a to URL identifikující objekt, který bude uložen do lokáního souborového systému do aktuálního adresáře. Pokud v dotazu URL není uvedeno jméno souboru, obsah bude uložen do souboru index.html. Program musí podporovat stavové kódy HTTP protokolu pro přesměrování požadavku 3xx. Oznámení o chybách, které mohou nastat, bude vytištěno na standardní chybový výstup (stderr). Za vnořený objekt považujte obrázek (nestahujte definici CSS, Javascript, Flash objekty atd.). Obrázky uložte do adresáře podle cesty, jaká je uvedena v HTML dokumentu.

webclient.c
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <unistd.h>
#include <netdb.h>
#include <string.h>
#include <ctype.h>
 
int webclient(char* url, unsigned short jumps) {
	if (jumps > 5) {
		fprintf(stderr, "D'OH! Too many jumps, my legs hurts!\n");
		return 1;
	}
 
	if (strstr(url, "://") != NULL) {
		url = strstr(url, "://") + strlen("://");
	}
 
	char* parsedhost = url;
	char* parsedport = "80";
	char* parsedurl = "";
	char* parsedfile = "index.htm";
	unsigned int i = 0;
	while (url[i] != '\0') {
		if (url[i] == ':') {
			url[i] = '\0';
			parsedport = url + i + 1;
		}
		if (url[i] == '/') {
			url[i] = '\0';
			parsedurl = url + i + 1;
			i++;
			while (url[i] != '\0') {
				if (url[i] == '/') {
					parsedfile = url + i + 1;
				}
				i++;
			}
			break;
		}
		i++;
	}
 
	if (strlen(parsedurl) < 1) {
		parsedurl = "";
	}
 
	//printf("Host: %s\nPort: %s\nURL:  %s\nFile: %s\n", parsedhost, parsedport, parsedurl, parsedfile); //DEBUG
 
	int s = socket(PF_INET, SOCK_STREAM, 0);
	if (s < 0) {
		fprintf(stderr, "D'OH! Broken socket, call electrician.\n");
		return 1;
	}
 
	struct sockaddr_in sadr;
	bzero(&sadr, sizeof(sadr)); //radsi to vynulujem
	sadr.sin_family = AF_INET; //rodina
	struct hostent *host;
	if ((host = gethostbyname(parsedhost)) == NULL) {
		fprintf(stderr, "D'OH! Unknown host.\n");
		return 1;
	}
	memcpy(&sadr.sin_addr, host->h_addr, host->h_length); //adresa
	sadr.sin_port = htons(atoi(parsedport));
 
	if (connect(s, (struct sockaddr*) &sadr, sizeof(sadr)) < 0) {
		fprintf(stderr, "D'OH! Server is dead.\n");
		return 1;
	}
	printf("Connected!\n");
 
	printf("Negotiating...\n");
	char* get = NULL;
	if (parsedurl == NULL) {
		parsedurl = "";
	}
	//printf("Processing HTTP GET...\n");
	get = malloc((strlen("GET /") + strlen(parsedurl) + strlen(" HTTP/1.0\r\nHost: ") + strlen(parsedhost) + strlen("\r\n\r\n")) * sizeof(char));
	if (get == NULL) {
		fprintf(stderr, "D'OH! Malloc fail, buy more RAM!\n");
		return 1;
	}
	get[0] = '\0';
	strcat(get, "GET /");
	strcat(get, parsedurl);
	strcat(get, " HTTP/1.0\r\nHost: ");
	strcat(get, parsedhost);
	strcat(get, "\r\n\r\n");
	//printf("%s\n", get);
	if ((write(s, get, strlen(get))) <= 0) {
		fprintf(stderr, "D'OH! Can't write.\n");
		if (parsedurl != NULL) {
			free(get);
		}
		return 1;
	}
	if (parsedurl != NULL) {
		free(get);
	}
 
	printf("Reading...\n");
	char* header;
	unsigned int allocated = 1;
	unsigned int dumped = 0;
	header = malloc(allocated * sizeof(char));
	if (header == NULL) {
		fprintf(stderr, "D'OH! Malloc fail, buy me more memory!\n");
		return 1;
	}
	while (strstr(header, "\r\n\r\n") == NULL) {
		read(s, header + dumped, 1);
		dumped++;
		if (dumped >= allocated) {
			allocated *= 2;
			header = realloc(header, allocated);
			if (header == NULL) {
				fprintf(stderr, "D'OH! Realloc fail, buy me more memory!\n");
				return 1;
			}
		}
	}
	//printf("Header:\n%s", header);
 
	unsigned int response = atoi(header + 9);
	printf("Response: %d\n", response);
 
	char* location = NULL;
	if (response >= 300 && response < 400) {
		location = strstr(header, "Location: ") + strlen("Location: ");
		i = 0;
		while (location[i] != '\r') {
			i++;
		}
		location[i] = '\0';
		//printf("\nLocation: %s\n", location);
	}
 
	if (response == 200) {
		//printf("Socket -> %s...\n", parsedfile);
		printf("Downloading...\n");
		FILE* fp = fopen(parsedfile, "w");
		if (fp == NULL) {
			fprintf(stderr, "D'OH! I don't know where to write, buy me some paper!\n");
			free(header);
			return 1;
		}
		char socketchar[1];
		while (read(s, socketchar, 1) > 0) {
			fwrite(socketchar, sizeof(char), 1, fp);
		}
		fclose(fp);
	}
	if (response >= 300 && response < 400) {
		printf("Redirected...\n");
		webclient(location, ++jumps);
	}
 
	free(header);
	shutdown(s, 2);
	close(s);
	return 0;
}
 
int main(int argc, char* argv[]) {
	if (argc > 2) {
		fprintf(stderr, "D'OH! Too many parameters.\n");
		return 1;
	}
 
	if (argc == 1) {
		printf("USAGE: webclinet URL\n");
		return 0;
	}
 
	return webclient(argv[1], 0);
}
Makefile
CC = gcc
CFLAGS = -O2 -std=c99 -pedantic -Wall -W -pipe
PROG = webclient
 
all: $(PROG)
 
webclient: webclient.c
 
clean:
	-rm -f $(PROG) *.htm *.html *.png *.gif *.jpg *.jpeg *.bmp
test.sh
#!/bin/bash
 
echo "Cleaning..."
make clean
echo
echo "Compiling..."
make
echo
echo "Downloading simple web page with images..."
./webclient http://www.fit.vutbr.cz
echo
echo "Downloading more complex URL (image)..."
./webclient http://www.fit.vutbr.cz:80/common/img/fit_logo_cz.gif
/var/www/wiki/data/pages/pitel/ipk/projekt1.txt · Poslední úprava: 30. 12. 2022, 13.43:01 autor: 127.0.0.1