[C] geturl →→→→→进入此内容的聊天室

来自 , 2021-02-20, 写在 C, 查看 127 次.
URL http://www.code666.cn/view/52cf49fe
  1. /*
  2.  * 没有解析服务器返回码
  3.  * 仅返回服务器发送的资源数据
  4.  * 数据大小最大支持 MAX_RCVBUF_LEN (800*1024)
  5.  *
  6.  */
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include <unistd.h>
  10. #include <string.h>
  11. #include <strings.h>
  12. #include <sys/socket.h>
  13. #include <netinet/in.h>
  14. #include <arpa/inet.h>
  15. #include <errno.h>
  16. #include <netdb.h>
  17.  
  18. #define DEFAULT_PORT 80
  19. #define CONTENT_LEN_STR "Content-Length"
  20. #define CHUNKED_STR "Transfer-Encoding: chunked"
  21. #define MAX_URL_LEN 2048
  22. #define MAX_BUF_LEN 2048
  23. #define MAX_IP_LEN 16
  24. #define MAX_RCVBUF_LEN (800*1024)
  25. #define CHUNK_SIZE_LEN 6
  26. #define CHUNK_END_STR "\r\n"
  27. #define CHUNK_END_STR_LEN 2
  28.  
  29. #define REQUEST_FORMART "GET %s HTTP/1.1\r\nHost:%s\r\nConnection: close\r\nUser-Agent: Mozilla/5.0 (X11; Linux i686) AppleWebKit/534.34 (KHTML, like Gecko) rekonq/1.1 Safari/534.34\r\nAccept: text/ihtml,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\nAccept-Encoding: \r\nAccept-Charset:utf-8,*;q=0.5\r\nAccept-Language: zh-CN, en-US; q=0.8, en; q=0.6\r\n\r\n"
  30.  
  31. struct url_parse_t {
  32.         char host[MAX_URL_LEN];
  33.         unsigned short port;
  34.         char resource[MAX_URL_LEN];
  35. };
  36.  
  37. static int parse_url(char *url, struct url_parse_t *url_parse)
  38. {
  39.         char *temp;
  40.         char *parse_p = url;
  41.         char host[1024] = {0};
  42.         char resource[1024] = {0};
  43.         int port = 80;
  44.  
  45.         if (temp = strstr(parse_p, "http://")) {
  46.                 parse_p = url + 7;
  47.         }
  48.  
  49.         if (temp = strstr(parse_p, "/")) {
  50.                 strncpy(host, parse_p, temp - parse_p);
  51.                 strcpy(resource, temp);
  52.         } else {
  53.                 strcpy(host, parse_p);
  54.                 resource[0] = '/';
  55.         }
  56.  
  57.         if (temp = strstr(host, ":")) {
  58.                 port = atoi(temp + 1);
  59.                 if (port <= 0) {
  60.                         return -1;
  61.                 }
  62.         }
  63.  
  64.         strcpy(url_parse->host, host);
  65.         strcpy(url_parse->resource, resource);
  66.         url_parse->port = port;
  67.         return 0;
  68. }
  69.  
  70. static int parse_proxy(char *proxy, char *ip, unsigned short *port)
  71. {
  72.         if (sscanf(proxy, "%[^':']:%hd", ip, port) != 2) {
  73.                 return -1;
  74.         }
  75.         return 0;
  76. }
  77.  
  78. static int read_full(int fd, char *buf, int content_len, int proxy_flag)
  79. {
  80.         int templen = 0;
  81.         int left_bytes = content_len;
  82.         while(left_bytes) {
  83.                 if ((templen = read(fd, buf + content_len - left_bytes, left_bytes)) < 0) {
  84.                         return -1;
  85.                 } else if (!templen && proxy_flag) {
  86.                         break;
  87.                 }
  88.                 left_bytes -= templen;
  89.         }
  90.         return content_len;
  91. }
  92.  
  93. //recved_bytes保存已接收的属于本块的数据
  94. //用于确定chunk-size
  95. //
  96. //return value:
  97. //0 for chunk-size == 0 传输结束
  98. //大于0 正常结束 本块接收完毕 可以开始接收下一块
  99. //-1 接收异常
  100. static int read_chunk(int fd, char *buf, const char *recved_bytes, int recved_size)
  101. {
  102.         char *temp;
  103.         char temp_buf[MAX_BUF_LEN];
  104.         const char *recved_p;
  105.         int chunk_len;
  106.         int rcvsize;
  107.         int bufoffset = 0;
  108.         //printf("in read chunk\n");
  109.  
  110.         if (recved_bytes) {
  111.                 //如果没有\r\n说明chunk-size没有接收完 需要继续接收
  112.                 if (!(temp = strstr(recved_bytes, "\r\n"))) {
  113.                         memcpy(temp_buf, recved_bytes, recved_size);
  114.                         if ((rcvsize = read_full(fd, temp_buf + recved_size, CHUNK_SIZE_LEN, 0)) < 0) {
  115.                                 return -1;
  116.                         }
  117.                         recved_size += CHUNK_SIZE_LEN;
  118.                         recved_p = temp_buf;
  119.                 } else {
  120.                         recved_p = recved_bytes;
  121.                 }
  122.         } else {
  123.                 if ((rcvsize = read_full(fd, temp_buf, CHUNK_SIZE_LEN/2, 0)) < 0) {
  124.                         return -1;
  125.                 }
  126.                 if (!strncmp(temp_buf, "0\r\n", CHUNK_SIZE_LEN/2)) {
  127.                         return 0;
  128.                 } else {
  129.                         if (rcvsize = read_full(fd, temp_buf + CHUNK_SIZE_LEN/2, CHUNK_SIZE_LEN - CHUNK_SIZE_LEN/2, 0) < 0) {
  130.                                 return -1;
  131.                         }
  132.                 }
  133.                 recved_p = temp_buf;
  134.                 recved_size = CHUNK_SIZE_LEN;
  135.         }
  136.  
  137.         sscanf(recved_p, "%x", &chunk_len);
  138.  
  139.         if (chunk_len < 1000) {
  140.                 printf("%s$$$$$", recved_p);
  141.         }
  142.         if (!chunk_len) {
  143.                 return chunk_len;
  144.         }
  145.  
  146.         if (!(temp = strstr(recved_p, CHUNK_END_STR))) {
  147.                 return -1;
  148.         }
  149.  
  150.         if (temp + CHUNK_END_STR_LEN == recved_p + recved_size) {
  151.                 recved_size = 0;
  152.                 bufoffset = 0;
  153.         } else if (temp + CHUNK_END_STR_LEN > recved_p + recved_size) {
  154.                 return -1;
  155.         } else {
  156.                 bufoffset = recved_size - (temp + CHUNK_END_STR_LEN - recved_p);
  157.                 memcpy(buf, temp + CHUNK_END_STR_LEN, bufoffset);
  158.         }
  159.  
  160.         if ((rcvsize = read_full(fd, buf + bufoffset, chunk_len - bufoffset, 0)) < 0) {
  161.                 return -1;
  162.         }
  163.         if (*(buf + bufoffset + rcvsize - 1) != '\n' && *(buf + bufoffset + rcvsize - 2) != '\r') {
  164.                 //clear the end "\r\n"
  165.                 if (read_full(fd, temp_buf, CHUNK_END_STR_LEN, 0) < 0) {
  166.                         return -1;
  167.                 }
  168.         }
  169.         *(buf + chunk_len) = 0;
  170.         return chunk_len;
  171. }
  172.  
  173. static int recv_page(int fd, char *buf, int proxy_flag, struct url_parse_t *parsed_url)
  174. {
  175.         char rcvbuf[MAX_BUF_LEN];
  176.         char resourcebuf[MAX_URL_LEN];
  177.         char *temp;
  178.         int content_len = MAX_RCVBUF_LEN - 1;
  179.         int bufoffset = 0;
  180.         int templen;
  181.         int rcvsize;
  182.         int chunk_return;
  183.  
  184.         if (proxy_flag) {
  185.                 sprintf(resourcebuf, "http://%s/%s", parsed_url->host, parsed_url->resource);
  186.         } else {
  187.                 sprintf(resourcebuf, "%s", parsed_url->resource);
  188.         }
  189.  
  190.         //sprintf(rcvbuf, REQUEST_FORMART, resourcebuf, parsed_url->host, parsed_url->port);
  191.         sprintf(rcvbuf, REQUEST_FORMART, resourcebuf, parsed_url->host);
  192.  
  193.         if (write(fd, rcvbuf, strlen(rcvbuf)) < 0) {
  194.                 return -1;
  195.         }
  196.  
  197.         rcvsize = read(fd, rcvbuf, sizeof(rcvbuf));
  198.         printf("rcvsize:%d, response:%s\n", rcvsize, rcvbuf);
  199.  
  200.         /*  
  201.          *   if "chunked"
  202.          *   loop:
  203.          *   send bytes num --n first
  204.          *   then n bytes data
  205.          *   do loop
  206.          *   stop when bytes num == 0 end with "\r\n"
  207.          *   then end all data end with "\r\n"
  208.          */
  209.         if (!proxy_flag) {
  210.                 if ((temp = strstr(rcvbuf, CONTENT_LEN_STR))) {
  211.                         sscanf(temp, "Content-Length:%d", &content_len);
  212.                 } else if (temp = strstr(rcvbuf, CHUNKED_STR)){
  213.                         content_len = 0;
  214.                 } else {
  215.                         return -1;
  216.                 }
  217.         }
  218.  
  219.         temp = strstr(rcvbuf, "\r\n\r\n");
  220.         //in case recv done.
  221.         if (content_len && content_len <= rcvsize - (temp + 4 - rcvbuf)) {
  222.                 memcpy(buf, temp + 4, content_len);
  223.                 buf[content_len] = 0;
  224.                 return 0;
  225.         }
  226.  
  227.         //content_len == 0 表示chunked模式
  228.         if (!proxy_flag && !content_len) {
  229.                 if (temp) {
  230.                         temp += 4;
  231.                         bufoffset = 0;
  232.                 }
  233.                 while((chunk_return = read_chunk(fd, buf + bufoffset, temp,
  234.                                                 rcvsize - (temp - rcvbuf))) >= 0) {
  235.                         if (chunk_return == 0) {
  236.                                 break;
  237.                         } else {
  238.                                 temp = NULL;
  239.                                 bufoffset += chunk_return;
  240.                         }
  241.                 }
  242.         } else {
  243.                 bufoffset = rcvsize - (temp + 4 - rcvbuf);
  244.                 memcpy(buf, temp + 4, bufoffset);
  245.                 if ((rcvsize = read_full(fd, buf + bufoffset, content_len - bufoffset, proxy_flag)) < 0) {
  246.                         return -1;
  247.                 }
  248.                 bufoffset += rcvsize;
  249.         }
  250.  
  251.         buf[bufoffset] = 0;
  252.         return 0;
  253. }
  254.  
  255. char *geturl(char *url, char *proxy)
  256. {
  257.         static char rcvbuf[MAX_RCVBUF_LEN];
  258.         int fd, content_len = 0;
  259.         char *temp_p;
  260.         char ipbuf[MAX_IP_LEN];
  261.  
  262.         struct sockaddr_in saddr;
  263.         int addrlen = sizeof(struct sockaddr_in);
  264.         unsigned short port;
  265.  
  266.         int proxy_flag = 0;
  267.  
  268.         struct hostent *hostinfo_p;
  269.         struct url_parse_t parsed_url;
  270.  
  271.         saddr.sin_family = AF_INET;
  272.         bzero(rcvbuf, MAX_RCVBUF_LEN);
  273.  
  274.         if (proxy) {
  275.                 if (parse_proxy(proxy, ipbuf, &port) < 0) {
  276.                         fprintf(stderr, "parse proxy error\n");
  277.                 } else {
  278.                         saddr.sin_addr.s_addr = inet_addr(ipbuf);
  279.                         saddr.sin_port = htons(port);
  280.                         proxy_flag = 1;
  281.                 }
  282.         }
  283.  
  284.         if (parse_url(url, &parsed_url) < 0) {
  285.                 fprintf(stderr, "parse url error");
  286.                 return NULL;
  287.         }
  288.  
  289.         if (!proxy_flag) {
  290.                 hostinfo_p = gethostbyname(parsed_url.host);
  291.                 saddr.sin_addr = *(struct in_addr *)(hostinfo_p->h_addr);
  292.                 saddr.sin_port = htons(parsed_url.port);
  293.         }
  294.  
  295.         if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
  296.                 perror("socket error");
  297.                 return NULL;
  298.         }
  299.  
  300.         if (connect(fd, (struct sockaddr *)&saddr, addrlen) < 0) {
  301.                 perror("connect error");
  302.                 return NULL;
  303.         }
  304.  
  305.         if (recv_page(fd, rcvbuf, proxy_flag, &parsed_url) < 0) {
  306.                 return NULL;
  307.         }
  308.  
  309.         return rcvbuf;
  310. }
  311.  
  312. int main(int argc, char **argv)
  313. {
  314.         char *temp;
  315.         if (argc != 2) {
  316.                 fprintf(stderr, "%s host\n", argv[0]);
  317.                 exit(1);
  318.         }
  319.         temp = geturl(argv[1], "110.4.12.170:80");
  320.         //temp = geturl(argv[1], NULL);
  321.         if (temp) {
  322.                 printf("%s\n", temp);
  323.         } else {
  324.                 printf("temp NULL\n");
  325.         }
  326.         return 0;
  327. }
  328.  

回复 "geturl"

这儿你可以回复上面这条便签

captcha