Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /* В программе присутствует обработка только ответа 200 ОК
- Не разделил модули по файлам, присутсвуют магические константы
- Можно было добавить обработку других кодов ответов HTTP,
- написав нормальный парсер для ответа.
- Времени потратил около 12-14 часов*/
- #define _GNU_SOURCE
- #include <arpa/inet.h>
- #include <netdb.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/socket.h>
- #include <unistd.h>
- typedef struct Url {
- char* scheme;
- char* login;
- char* password;
- char* hostname;
- char* port;
- char* path;
- char* query;
- char* fragment;
- } Url;
- int parser(char* url, Url* parsing, int flag);
- int parse_origin(char* origin, char* end, Url* parsing);
- char* check_login_password(char* origin, Url* parsing);
- int check_scheme(char* str, char** port);
- char* parse_path(char* origin, Url* parsing);
- char* parse_query(char* path, Url* parsing);
- char* parse_fragment(char* query, Url* parsing);
- char* parse_for_request(char* origin, Url* parsing);
- void init_sockaddr (struct sockaddr_in *name,
- const char* hostname,
- uint16_t port);
- char* do_request(Url* parsing);
- int parse_recieve(char* buffer);
- int write_rec_to_file(char* buffer, FILE* file, int sock);
- void free_url(Url* parsing);
- int main(int argc, char **argv) {
- if (argc != 2) {
- return -3;
- }
- char buffer[4096] = {};
- Url* parsing = calloc(1, sizeof(Url));
- if(!parsing) {
- return -4;
- }
- char* url = argv[1];
- struct sockaddr_in address = {};
- int sock = socket(AF_INET, SOCK_STREAM, 0);
- if (parser(url, parsing, 0)) {
- return -1;
- }
- char* request_m = do_request(parsing);
- init_sockaddr(&address, parsing->hostname, atoi(parsing->port));
- if (connect(sock, (struct sockaddr*)&address, sizeof(address)) < 0) {
- free(request_m);
- free_url(parsing);
- free(parsing);
- return -2;
- }
- send(sock, request_m, strlen(request_m) + 1, 0);
- free(request_m);
- FILE* file = fopen("file", "w");
- if (!file) {
- free_url(parsing);
- free(parsing);
- }
- write_rec_to_file(buffer, file, sock);
- free_url(parsing);
- free(parsing);
- close(sock);
- fclose(file);
- return 0;
- }
- char* check_login_password(char* origin, Url* parsing) {
- char* field = strstr(origin, "@");
- if (!field) {
- parsing->password = NULL;
- parsing->login = NULL;
- return NULL;
- }
- char* separator = strstr(origin, ":");
- if (!separator) {
- return field + 1;
- }
- asprintf(&parsing->login, "%.*s", (int)(separator - origin), origin);
- asprintf(&parsing->password,"%.*s", (int)(field - separator - 1), separator + 1);
- return field + 1;
- }
- int parse_origin(char* origin, char* end, Url* parsing) {
- char* host = check_login_password(origin, parsing);
- if (host) {
- origin = host;
- }
- char* port = strstr(origin, ":");
- if (port) {
- asprintf(&parsing->hostname, "%.*s", (int)(port - origin), origin);
- asprintf(&parsing->port, "%.*s", (int)(end - port - 1), port + 1);
- return 0;
- }
- asprintf(&parsing->hostname, "%.*s", (int)(end - origin), origin);
- return 1;
- }
- int check_scheme(char* str, char** port) {
- int flag_http = 0;
- int flag_https = 0;
- if (!strcmp(str, "http")) {
- flag_http = 1;
- *port = "80";
- return 1;
- }
- if (!strcmp(str, "https")) {
- flag_https = 1;
- *port = "443";
- return 1;
- }
- return 0;
- }
- char* parse_path(char* origin, Url* parsing) {
- if (!(origin + 1)) {
- return NULL;
- }
- int i = 0;
- while (origin[i] && origin[i] != '?' && origin[i] != '#') {
- i++;
- }
- asprintf(&parsing->path, "%.*s", (int)(i), origin);
- return origin + i;
- }
- char* parse_query(char* path, Url* parsing) {
- if (!(path + 1)) {
- return NULL;
- }
- int i = 0;
- while (path[i] && path[i] != '#') {
- i++;
- }
- asprintf(&parsing->query, "%.*s", (int)(i), path);
- return path + i;
- }
- char* parse_fragment(char* query, Url* parsing) {
- if (!(query + 1)) {
- return NULL;
- }
- int i = 0;
- while (query[i]) {
- i++;
- }
- asprintf(&parsing->fragment, "%.*s", (int)(i), query);
- return query;
- }
- char* parse_for_request(char* origin, Url* parsing) {
- if (!(origin + 1)) {
- return NULL;
- }
- int i = 0;
- while (origin[i] && origin[i] != '#') {
- i++;
- }
- asprintf(&parsing->path, "%.*s", (int)(i), origin);
- return origin + i;
- }
- int parser(char* url, Url* parsing, int flag) {
- char* str = NULL;
- int size = strlen(url);
- char* field = strstr(url, "://");
- if (!field) {
- return -1;
- }
- asprintf(&str, "%.*s", (int)(field - url), url);
- if (!check_scheme(str, &parsing->port)) {
- return -2;
- }
- parsing->scheme = str;
- char* origin = strstr(field + 3, "/");
- if (!origin) {
- parse_origin(field + 3, url + size, parsing);
- asprintf(&parsing->path, "%.*s", 1, str);
- return 0;
- }
- parse_origin(field + 3, origin, parsing);
- char* path = parse_for_request(origin, parsing);
- if (flag != 0) {
- path = parse_path(origin, parsing);
- }
- if (!*(path) || !path || *(path) == '#') {
- if (*(path) == '#') {
- char* fragment = parse_fragment(path, parsing);
- }
- return 0;
- }
- char* query = parse_query(path, parsing);
- if (!*(query) || !query) {
- return 0;
- }
- char* fragment = parse_fragment(query, parsing);
- return 0;
- }
- void init_sockaddr (struct sockaddr_in *name,
- const char* hostname,
- uint16_t port) {
- struct hostent* hostinfo;
- name->sin_family = AF_INET;
- name->sin_port = htons(80);
- hostinfo = gethostbyname(hostname);
- if (hostinfo == NULL) {
- fprintf (stderr, "Unknown host %s.\n", hostname);
- exit (EXIT_FAILURE);
- }
- name->sin_addr = *(struct in_addr*)hostinfo->h_addr;
- }
- char* do_request(Url* parsing) {
- char* request = NULL;
- int size = strlen(parsing->path);
- int host_size = strlen(parsing->hostname) + 11;
- int new_size = asprintf(&request, "GET %.*s HTTP/1.1\r\n", size, parsing->path);
- char* new_request = realloc(request, new_size + host_size);
- if (!new_request) {
- free(request);
- return NULL;
- }
- request = new_request;
- snprintf(request + new_size, host_size, "Host: %s\r\n\r\n", parsing->hostname);
- return request;
- }
- int parse_recieve(char* buffer) {
- char* new_line = strstr(buffer, "\r\n");
- if (!new_line) {
- return -1;
- }
- char* check_str = NULL;
- int size = asprintf(&check_str, "%.*s", (int)(new_line - buffer), buffer);
- char* ok = strstr(check_str, "200 OK");
- if (!ok) {
- free(check_str);
- return -2;
- }
- free(check_str);
- return 0;
- }
- void free_url(Url* parsing) {
- if (parsing->scheme) {
- free(parsing->scheme);
- }
- if (parsing->login) {
- free(parsing->login);
- }
- if (parsing->password) {
- free(parsing->password);
- }
- if (parsing->hostname) {
- free(parsing->hostname);
- }
- if (parsing->port) {
- //free(parsing->port);
- }
- if (parsing->path) {
- free(parsing->path);
- }
- if (parsing->query) {
- free(parsing->query);
- }
- if (parsing->fragment) {
- free(parsing->fragment);
- }
- }
- int write_rec_to_file(char* buffer, FILE* file, int sock) {
- int nbytes_total = 0;
- int flag = 0;
- int i = 0;
- char* check = NULL;
- char* end = NULL;
- while ((nbytes_total = read(sock, buffer, 4095)) > 0) {
- if (!i && parse_recieve(buffer)) {
- return 0;
- }
- if (!flag) {
- end = strstr(buffer, "\r\n\r\n");
- if (!end) {
- i++;
- continue;
- }
- flag = 1;
- write(fileno(file), buffer + (end - buffer) + 4, nbytes_total - (end - buffer) - 4);
- i++;
- continue;
- }
- check = strstr(buffer, "HTTP/1.1 400");
- if (check) {
- write(fileno(file), buffer, check - buffer);
- break;
- }
- write(fileno(file), buffer, nbytes_total);
- i++;
- }
- return 1;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement