Advertisement
Guest User

Untitled

a guest
Dec 9th, 2019
325
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 8.76 KB | None | 0 0
  1. /* В программе присутствует обработка только ответа 200 ОК
  2.    Не разделил модули по файлам, присутсвуют магические константы
  3.    Можно было добавить обработку других кодов ответов HTTP,
  4.    написав нормальный парсер для ответа.
  5.  
  6.    Времени потратил около 12-14 часов*/
  7.  
  8.  
  9. #define _GNU_SOURCE
  10.  
  11. #include <arpa/inet.h>
  12. #include <netdb.h>
  13. #include <stdio.h>
  14. #include <stdlib.h>
  15. #include <string.h>
  16. #include <sys/socket.h>
  17. #include <unistd.h>
  18.  
  19. typedef struct Url {
  20.     char* scheme;
  21.     char* login;
  22.     char* password;
  23.     char* hostname;
  24.     char* port;
  25.     char* path;
  26.     char* query;
  27.     char* fragment;
  28. } Url;
  29.  
  30.  
  31. int parser(char* url, Url* parsing, int flag);
  32. int parse_origin(char* origin, char* end, Url* parsing);
  33. char* check_login_password(char* origin, Url* parsing);
  34. int check_scheme(char* str, char** port);
  35. char* parse_path(char* origin, Url* parsing);
  36. char* parse_query(char* path, Url* parsing);
  37. char* parse_fragment(char* query, Url* parsing);
  38. char* parse_for_request(char* origin, Url* parsing);
  39.  
  40.  
  41. void init_sockaddr (struct sockaddr_in *name,
  42.                 const char* hostname,
  43.                 uint16_t port);
  44. char* do_request(Url* parsing);
  45.  
  46. int parse_recieve(char* buffer);
  47. int write_rec_to_file(char* buffer, FILE* file, int sock);
  48.  
  49. void free_url(Url* parsing);
  50.  
  51.  
  52. int main(int argc, char **argv) {
  53.     if (argc != 2) {
  54.         return -3;
  55.     }
  56.  
  57.     char buffer[4096] = {};
  58.  
  59.     Url* parsing = calloc(1, sizeof(Url));
  60.  
  61.     if(!parsing) {
  62.         return -4;
  63.     }
  64.  
  65.     char* url = argv[1];
  66.  
  67.     struct sockaddr_in address = {};
  68.  
  69.     int sock = socket(AF_INET, SOCK_STREAM, 0);
  70.  
  71.     if (parser(url, parsing, 0)) {
  72.         return -1;
  73.     }
  74.  
  75.     char* request_m = do_request(parsing);
  76.  
  77.     init_sockaddr(&address, parsing->hostname, atoi(parsing->port));
  78.  
  79.     if (connect(sock, (struct sockaddr*)&address, sizeof(address)) < 0) {
  80.         free(request_m);
  81.         free_url(parsing);
  82.         free(parsing);
  83.         return -2;
  84.     }
  85.  
  86.     send(sock, request_m, strlen(request_m) + 1, 0);
  87.     free(request_m);
  88.  
  89.     FILE* file = fopen("file", "w");
  90.     if (!file) {
  91.         free_url(parsing);
  92.         free(parsing);
  93.     }
  94.  
  95.     write_rec_to_file(buffer, file, sock);
  96.  
  97.     free_url(parsing);
  98.     free(parsing);
  99.     close(sock);
  100.     fclose(file);
  101.  
  102.     return 0;
  103. }
  104.  
  105. char* check_login_password(char* origin, Url* parsing) {
  106.     char* field = strstr(origin, "@");
  107.  
  108.     if (!field) {
  109.         parsing->password = NULL;
  110.         parsing->login = NULL;
  111.         return NULL;
  112.     }
  113.  
  114.     char* separator = strstr(origin, ":");
  115.     if (!separator) {
  116.         return field + 1;
  117.     }
  118.  
  119.     asprintf(&parsing->login, "%.*s", (int)(separator - origin), origin);
  120.     asprintf(&parsing->password,"%.*s", (int)(field - separator - 1), separator + 1);
  121.  
  122.     return field + 1;
  123. }
  124.  
  125.  
  126. int parse_origin(char* origin, char* end, Url* parsing) {
  127.     char* host = check_login_password(origin, parsing);
  128.  
  129.     if (host) {
  130.         origin = host;
  131.     }
  132.  
  133.     char* port = strstr(origin, ":");
  134.  
  135.     if (port) {
  136.         asprintf(&parsing->hostname, "%.*s", (int)(port - origin), origin);
  137.         asprintf(&parsing->port, "%.*s", (int)(end - port - 1), port + 1);
  138.         return 0;
  139.     }
  140.  
  141.     asprintf(&parsing->hostname, "%.*s", (int)(end - origin), origin);
  142.     return 1;
  143. }
  144.  
  145. int check_scheme(char* str, char** port) {
  146.     int flag_http = 0;
  147.     int flag_https = 0;
  148.  
  149.     if (!strcmp(str, "http")) {
  150.         flag_http = 1;
  151.         *port = "80";
  152.         return 1;
  153.     }
  154.  
  155.     if (!strcmp(str, "https")) {
  156.         flag_https = 1;
  157.         *port = "443";
  158.         return 1;
  159.     }
  160.  
  161.     return 0;
  162. }
  163.  
  164. char* parse_path(char* origin, Url* parsing) {
  165.     if (!(origin + 1)) {
  166.         return NULL;
  167.     }
  168.  
  169.     int i = 0;
  170.     while (origin[i] && origin[i] != '?' && origin[i] != '#') {
  171.         i++;
  172.     }
  173.  
  174.     asprintf(&parsing->path, "%.*s", (int)(i), origin);
  175.     return origin + i;
  176. }
  177.  
  178. char* parse_query(char* path, Url* parsing) {
  179.     if (!(path + 1)) {
  180.         return NULL;
  181.     }
  182.  
  183.     int i = 0;
  184.     while (path[i] && path[i] != '#') {
  185.         i++;
  186.     }
  187.  
  188.     asprintf(&parsing->query, "%.*s", (int)(i), path);
  189.     return path + i;
  190. }
  191.  
  192. char* parse_fragment(char* query, Url* parsing) {
  193.     if (!(query + 1)) {
  194.         return NULL;
  195.     }
  196.  
  197.     int i = 0;
  198.     while (query[i]) {
  199.         i++;
  200.     }
  201.  
  202.     asprintf(&parsing->fragment, "%.*s", (int)(i), query);
  203.     return query;
  204. }
  205.  
  206. char* parse_for_request(char* origin, Url* parsing) {
  207.     if (!(origin + 1)) {
  208.         return NULL;
  209.     }
  210.  
  211.     int i = 0;
  212.     while (origin[i] && origin[i] != '#') {
  213.         i++;
  214.     }
  215.  
  216.     asprintf(&parsing->path, "%.*s", (int)(i), origin);
  217.     return origin + i;
  218. }
  219.  
  220. int parser(char* url, Url* parsing, int flag) {
  221.     char* str = NULL;
  222.     int size = strlen(url);
  223.     char* field = strstr(url, "://");
  224.  
  225.     if (!field) {
  226.         return -1;
  227.     }
  228.  
  229.     asprintf(&str, "%.*s", (int)(field - url), url);
  230.  
  231.     if (!check_scheme(str, &parsing->port)) {
  232.         return -2;
  233.     }
  234.  
  235.     parsing->scheme = str;
  236.     char* origin = strstr(field + 3, "/");
  237.  
  238.     if (!origin) {
  239.         parse_origin(field + 3, url + size, parsing);
  240.         asprintf(&parsing->path, "%.*s", 1, str);
  241.         return 0;
  242.     }
  243.  
  244.     parse_origin(field + 3, origin, parsing);
  245.     char* path = parse_for_request(origin, parsing);
  246.  
  247.     if (flag != 0) {
  248.         path = parse_path(origin, parsing);
  249.     }
  250.  
  251.     if (!*(path) || !path || *(path) == '#') {
  252.         if (*(path) == '#') {
  253.             char* fragment = parse_fragment(path, parsing);
  254.         }
  255.         return 0;
  256.     }
  257.  
  258.     char* query = parse_query(path, parsing);
  259.  
  260.     if (!*(query) || !query) {
  261.         return 0;
  262.     }
  263.  
  264.     char* fragment = parse_fragment(query, parsing);
  265.     return 0;
  266.  
  267. }
  268.  
  269.  
  270. void init_sockaddr (struct sockaddr_in *name,
  271.                 const char* hostname,
  272.                 uint16_t port) {
  273.  
  274.   struct hostent* hostinfo;
  275.  
  276.   name->sin_family = AF_INET;
  277.   name->sin_port = htons(80);
  278.   hostinfo = gethostbyname(hostname);
  279.  
  280.   if (hostinfo == NULL) {
  281.       fprintf (stderr, "Unknown host %s.\n", hostname);
  282.       exit (EXIT_FAILURE);
  283.     }
  284.  
  285.   name->sin_addr = *(struct in_addr*)hostinfo->h_addr;
  286. }
  287.  
  288.  
  289. char* do_request(Url* parsing) {
  290.     char* request = NULL;
  291.     int size = strlen(parsing->path);
  292.     int host_size = strlen(parsing->hostname) + 11;
  293.     int new_size = asprintf(&request, "GET %.*s HTTP/1.1\r\n", size, parsing->path);
  294.     char* new_request = realloc(request, new_size + host_size);
  295.  
  296.     if (!new_request) {
  297.         free(request);
  298.         return NULL;
  299.     }
  300.  
  301.     request = new_request;
  302.     snprintf(request + new_size, host_size, "Host: %s\r\n\r\n", parsing->hostname);
  303.  
  304.     return request;
  305. }
  306.  
  307.  
  308. int parse_recieve(char* buffer) {
  309.     char* new_line = strstr(buffer, "\r\n");
  310.  
  311.     if (!new_line) {
  312.         return -1;
  313.     }
  314.  
  315.     char* check_str = NULL;
  316.     int size = asprintf(&check_str, "%.*s", (int)(new_line - buffer), buffer);
  317.    
  318.     char* ok = strstr(check_str, "200 OK");
  319.  
  320.     if (!ok) {
  321.         free(check_str);
  322.         return -2;
  323.     }
  324.  
  325.     free(check_str);
  326.     return 0;
  327. }
  328.  
  329. void free_url(Url* parsing) {
  330.     if (parsing->scheme) {
  331.         free(parsing->scheme);
  332.     }
  333.     if (parsing->login) {
  334.         free(parsing->login);
  335.     }
  336.     if (parsing->password) {
  337.         free(parsing->password);
  338.     }
  339.     if (parsing->hostname) {
  340.         free(parsing->hostname);
  341.     }
  342.     if (parsing->port) {
  343.         //free(parsing->port);
  344.     }
  345.     if (parsing->path) {
  346.         free(parsing->path);
  347.     }
  348.     if (parsing->query) {
  349.         free(parsing->query);
  350.     }
  351.     if (parsing->fragment) {
  352.         free(parsing->fragment);
  353.     }
  354.  
  355. }
  356.  
  357. int write_rec_to_file(char* buffer, FILE* file, int sock) {
  358.     int nbytes_total = 0;
  359.     int flag = 0;
  360.     int i = 0;
  361.  
  362.     char* check = NULL;
  363.     char* end = NULL;
  364.  
  365.     while ((nbytes_total = read(sock, buffer, 4095)) > 0) {
  366.         if (!i && parse_recieve(buffer)) {
  367.             return 0;
  368.         }
  369.  
  370.         if (!flag) {
  371.             end = strstr(buffer, "\r\n\r\n");
  372.             if (!end) {
  373.                 i++;
  374.                 continue;
  375.             }
  376.  
  377.             flag = 1;
  378.             write(fileno(file), buffer + (end - buffer) + 4, nbytes_total - (end - buffer) - 4);
  379.             i++;
  380.             continue;
  381.         }
  382.  
  383.         check = strstr(buffer, "HTTP/1.1 400");
  384.  
  385.         if (check) {
  386.             write(fileno(file), buffer, check - buffer);
  387.             break;
  388.         }
  389.  
  390.         write(fileno(file), buffer, nbytes_total);
  391.         i++;
  392.     }
  393.     return 1;
  394. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement