Skip to content

Instantly share code, notes, and snippets.

@Lhy121125
Created December 25, 2022 20:08
Show Gist options
  • Select an option

  • Save Lhy121125/2d6b0efa1f473baa92c512e002fa3b5a to your computer and use it in GitHub Desktop.

Select an option

Save Lhy121125/2d6b0efa1f473baa92c512e002fa3b5a to your computer and use it in GitHub Desktop.
A http Client that Works Similar to wget
// Because we are using POSIX features that aren't part of the C standard, we
// need to #define this macro before #including standard library headers to be
// granted access to POSIX-specific definitions such as struct addrinfo.
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
/*
* Convenient error handler for printing errno-associated message and exit(1).
*/
static void die(char *msg) {
perror(msg);
exit(1);
}
int main(int argc, char **argv){
if(argc != 4){
fprintf(stderr, "Usage: %s <host-name> <port-number> <URI>\n ex) ./http-client www.example.com 80/index.html\n",argv[0]);
exit(1);
}
char *server_ip = argv[1];
char *server_port = argv[2];
char *URI = argv[3];
//Obtain server address info using getaddrinfo()
struct addrinfo hints;//the struct we receving the actual answer
memset(&hints, 0, sizeof(hints));
// Specify what kind of connection we intend to make; these values tell
// getaddrinfo() that we don't care about other kinds of addresses.
hints.ai_family = AF_INET; // Only accept IPv4 addresses
hints.ai_socktype = SOCK_STREAM; // stream socket for TCP connections
hints.ai_protocol = IPPROTO_TCP; // TCP protocol
// Define where getaddrinfo() will return the information it found.
struct addrinfo *info;
// Call getaddrinfo(), specifying the server IP address and port as strings.
// getaddrinfo() will parse those for us and point info to the result.
int addr_err;
if ((addr_err = getaddrinfo(server_ip, server_port, &hints, &info)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(addr_err));
exit(1);
}
/*
* Create socket() and connect() it to server.
*/
// Create socket() according to the address family, socket type, and
// protocol of the address info.
int serv_fd = socket(info->ai_family, info->ai_socktype, info->ai_protocol);
if (serv_fd < 0)
die("socket");
// Connect socket with server address; the IP address and port in
// info->ai_addr should be the same address and port that getaddrinfo()
// parsed from server_address and server_port.
if (connect(serv_fd, info->ai_addr, info->ai_addrlen) < 0)
die("connect");
freeaddrinfo(info);
//Specific to this lab
FILE *fpw = fdopen(serv_fd,"wb");
if (fpw == NULL)
die("1: fdopen (for writing)");
setlinebuf(fpw);
/*FILE *fpr = fdopen(dup(serv_fd),"rb");
if (fpr == NULL)
die("2: fdopen (for reading)");
setlinebuf(fpr);
*/
//Send Http request
//char* request;
char buff[8192] = "";
char* request = strcat(buff,"GET ");
request = strcat(buff,URI);
request = strcat(buff," HTTP/1.0\r\nHost: ");
request = strcat(buff,server_ip);
request = strcat(buff,":");
request = strcat(buff,server_port);
request = strcat(buff,"\r\n\r\n");
printf("%s",request);
fwrite(request,1,8192,fpw);
// send(serv_fd, request, 8192, 0);
/*
FILE *fpw = fdopen(serv_fd,"wb");
if (fpw == NULL)
die("fdopen (for writing)")
FILE *fpr = fdopen(dup(serv_fd),"rb");
if (fpr == NULL)
die("fdopen (for reading)")
*/
FILE *fpr = fdopen(dup(serv_fd),"rb");
if (fpr == NULL)
die("2: fdopen (for reading)");
setlinebuf(fpr);
char buf[8192] = "";
char* first_line = fgets(buf,sizeof(buf),fpr);
printf("%s",first_line);
if(first_line == NULL){
printf("%s",buf);
die("1: fget(the fist line)");
}
//skip the http/1.0 and see whether the 9th char is 200
if(strncmp("200",buf+9,3) != 0){
printf("%s",buf);
die("400 bad request");
}
//get rid of header
while(1){
if(fgets(buf,8192,fpr) == NULL){
die("No \r\n");
}
if(strcmp(buf,"\r\n")==0){
break;
}
}
//Output file
FILE *fpo = fopen(strrchr(URI,'/')+1,"wb");
if (fpo == NULL)
die("fopen (for writing)");
// FILE pointers are block-buffered by default;
// configure fpw to be line-buffered.
setlinebuf(fpo);
//char buf[8192];
//Write the files from the response to the output file
size_t line_size;
while((line_size = fread(buf,1,8192,fpr))>0){
size_t write_size = fwrite(buf,1,line_size,fpo);
if(write_size != line_size){
die("writing something not expected");
}
}
fclose(fpr);
fclose(fpw);
fclose(fpo);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment