====== 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.
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
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);
}
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
#!/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