⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 http.c

📁 多线程 http资源下载工具 给予linux平台的。还凑合。有bug给我联系
💻 C
📖 第 1 页 / 共 2 页
字号:
#include <strings.h>#include <stdio.h>#include <string.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <netinet/in.h>#include <netinet/tcp.h>#include <sys/epoll.h>#include <unistd.h>#include <netdb.h>#include <errno.h>#include <stdlib.h>#include <arpa/inet.h>#include <pthread.h>#include "http.h"#include "function_restart.h"char *base_name (const char *);extern struct resource_info resource;extern struct file_range *files_range;extern struct command cmd;extern pthread_mutex_t mutex_cmd;extern pthread_cond_t cond_cmd_set;extern pthread_cond_t cond_cmd_clear;extern int pipe_recv_send[2];int recv_response_head_file (int, void *const, size_t);void retry (int, struct file_range * const);void update_file_range (struct file_range *, size_t);void close_connect (const int, struct file_range *const);void close_connects (int);size_t c_ntolower (char *const, size_t);inline char c_tolower (char *const);struct file_range *get_new_connect (int);struct file_range *fd_to_file_range (int);int safe_http_code (const char);int print_result (size_t);void print_resource_info (void);void print_resource_size (void);void print_size_human (size_t);void clear_cmd (struct command *const);void send_cmd (const struct command *);void wait_cmd (struct command *const);void epoll_remove (int, int);int epoll_add (int, int);inline int readable (struct epoll_event *);int parse_url_http (struct url_http *const, char *const);void clear_file_range (struct file_range *);char *base_name (const char *path){  char *base;  return (char *)((base = strrchr (path, '/'))? (base + 1): path);}int parse_url_http (struct url_http *const uh, char *const url){  size_t len_url;  size_t len_scheme;  char *scheme_sfix;  char *domain;  char *port;  char *path;        /* is scheme http ? */  scheme_sfix = strstr (url, "://");  len_scheme = scheme_sfix - url;  while (0 != len_scheme)    {            if (LEN_SCHEME_HTTP == len_scheme) 	{	  c_ntolower (url, LEN_SCHEME_HTTP);	  if (0 == strncmp (url, SCHEME_HTTP, LEN_SCHEME_HTTP))	    break;	}      fprintf (stderr, "invalid protocol.\n");      return -1;    }    /* is the length of url avalid ? */  len_url = strlen (url) - len_scheme - sizeof ("://") + 1;  if (MIN_LEN_URL_HTTP > len_url || MAX_LEN_URL_HTTP < len_url)    {      fprintf (stderr, "invalid length of URL.\n");      return -1;    }    domain = url + len_scheme;  domain += (0 != len_scheme)? (sizeof ("://") - 1): 0;  (*uh).domain = domain;    port = strchr (domain, ':');  path = strchr (domain, '/');    if (NULL != ((*uh).path = path))    {            (*uh).port = port + 1;      if ((NULL == port) || (port > path)) /* port is empty. */	(*uh).len_port = 0;      else			/* port is't empty */	(*uh).len_port = (path - (port + 1));      if ((MIN_LEN_PORT > (*uh).len_port) || (MAX_LEN_PORT < (*uh).len_port))	{	  fprintf (stderr, "the length of URL port is invalid.\n");	  return -1;	}      (*uh).len_path = strlen (path);      if (MIN_LEN_PATH > (*uh).len_path || MAX_LEN_PATH < (*uh).len_path)	goto __FUNCTION__invalid_path;      (*uh).len_domain = (len_url - (*uh).len_port - (*uh).len_path);      if (0 != (*uh).len_port)	(*uh).len_domain--;            if ((MIN_LEN_DOMAIN > (*uh).len_domain) || (MAX_LEN_DOMAIN < (*uh).len_domain))	{	  fprintf (stderr, "the length of URL domain is invalid.\n");	  return -1;	}            return 0;    } __FUNCTION__invalid_path:  fprintf (stderr, "the length of URL path is invalid.\n");  return -1;}int get_resource_size (char *const buf){  char content_length[10];  long int size;  int retval = 0;    char *p;  char *terminal;  unsigned char  i = 0;  int errno_old = errno;  if ((NULL == (p = strstr (buf, CONTENT_LENGTH))))    return -1;    p += LEN_CONTENT_LENGTH;  terminal = strstr(p, HEAD_TERMINAL);  while (C_ISBLANK (*p)) p++;  if (':' != *p)    goto __FUNCTION__error;  p++;  while (C_ISBLANK (*p)) p++;  while (C_ISNUM (*p) && i < (sizeof (content_length) - 1))    {      content_length[i] = *p;      i++;      p++;    }    while (!C_ISBLANK (*p)) p++;  if (p < terminal)    goto __FUNCTION__error;  content_length[i] = '\0';  errno_old = errno;  errno = 0;    size = strtol (content_length, NULL, 10);  if (0 != errno)    goto __FUNCTION__error;  resource.size = (size_t) size;  retval = 0;   __FUNCTION__error:  errno = errno_old;  return retval;}int safe_http_code (const char c){  if (C_ISNUM (c))    return 1;  if (C_ISALPHA (c))    return 1;  switch (c)  {  case '%':  case '/':  case '.':  case '#':  case '?':  case ';':  case ':':  case '-':    return 1;  default:    return 0;  }}int get_redirect_url (char *const buf, char *const url, const size_t size_url){  char *p;  char *p_remain;  size_t i = 0;  if ((NULL == url) || (0 == size_url))    {      fprintf (stderr, "no room for URL.\n");      return -1;    }    *(url + size_url - 1) = '\0';  p = strstr (buf, CONTENT_PFIX);  if (NULL == p)    goto __FUNCTION__invalid_url;  p += LEN_CONTENT_PFIX;  while (C_ISBLANK (*p)) p++;  if (':' != *p)        goto  __FUNCTION__invalid_url;  p++;  while (C_ISBLANK (*p)) p++;    p_remain = url;  while (safe_http_code (*p) && i < (size_url - 1))    {      *p_remain = *p;      p_remain++;      p++;      i++;    }  if (safe_http_code (*p))    {      fprintf (stderr, "redirect URL it too long.\n");      return -1;    }  while (C_ISBLANK (*p)) p++;  if (*p == '\r')    {      *p_remain = '\0';      return 0;    } __FUNCTION__invalid_url:  fprintf (stderr, "redirect URL is invalid.\n");  return -1;}int strtoshort (char *const s, short *size){  int errno_old;  long int tosize;  int retval = -1;  char *end;    errno_old = errno;  errno = 0;  tosize = strtol (s, &end, 10);  if ((0 != errno) || ('\0' != *end))    goto __FUNCTION__error;      if ((0 >= tosize) || ((MAX_PORT < tosize)))    goto __FUNCTION__error;  *size = tosize;  retval = 0; __FUNCTION__error:  errno = errno_old;  return retval;}int setup_sockaddr (struct sockaddr_in *const sock, struct url_http * const uh){  struct hostent *host;  short p;  char domain[MAX_LEN_DOMAIN + 1];  char port[MAX_LEN_PORT + 1];  strncpy (port, (*uh).port, (*uh).len_port);  if (0 == (*uh).len_port)    p = 80;  else if (((*uh).len_port > MAX_LEN_PORT) || (-1 == strtoshort (port, &p)))    {      fprintf (stderr, "invalid server port.\n");      return -1;    }  strncpy (domain, (*uh).domain, (*uh).len_domain);  *(domain + (*uh).len_domain) = '\0';  if (NULL == (host = gethostbyname (domain)))    {      fprintf (stderr, "%s.\n", hstrerror (h_errno));      fprintf (stderr, "can't get server address.\n");      return -1;    }      bzero (sock, SIZE_SOCKADDR);  (*sock).sin_family = (*host).h_addrtype;  (*sock).sin_port = htons (p);  (*sock).sin_addr = *((struct in_addr *) host->h_addr);  return 0;}int send_request_head_file (struct sockaddr_in *const sockaddr,	\			    struct url_http *const uh){  int fd_sock;  int sockopt;    if (-1 == (fd_sock = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP)))    {      fprintf (stderr, "create socket failure.\n");      return -1;    }    if (-1 == connect (fd_sock, (struct sockaddr *) sockaddr, SIZE_SOCKADDR))    {      close_restart (fd_sock);      fprintf (stderr, "connect to server failure.\n");      return -1;    }    if (-1 == send_restart (fd_sock, "HEAD ", (sizeof ("HEAD ") - 1), MSG_MORE))    goto __FUNCTION__SEND_FAILURE;  if (-1 == send_restart (fd_sock, (*uh).path, (*uh).len_path, MSG_MORE))    goto __FUNCTION__SEND_FAILURE;    if (-1 == send_restart (fd_sock, " HTTP/1.0\r\n\r\n", 13, 0))    goto __FUNCTION__SEND_FAILURE;    sockopt = 1;  setsockopt (fd_sock, SOL_SOCKET, TCP_NODELAY, (void *) &sockopt, SIZE_INT);  return fd_sock;   __FUNCTION__SEND_FAILURE:  fprintf (stderr, "send request to server failure.\n");  close_restart (fd_sock);  return -1;}int recv_response_head_file (int fd_sock, void *const buf, size_t size_buf){  ssize_t nbytes_recv;  void *remain;  void *next;  size_t size_remain;  char *p;  int search = 0;    remain = buf;  next = remain;  size_remain = size_buf - 2;  *(char *)(buf + size_remain + 1) = '\0';  while (1)    {      if (-1 != (nbytes_recv = recv (fd_sock, remain, size_remain, 0)))	{	  remain += nbytes_recv;	  size_remain -= nbytes_recv;	  	  	  *(char *) remain = '\0';	  	  if (0 == search)	    {	      if (remain - buf < LEN_CONTENT_PFIX)		continue;	      	      search = 1;	    }	  	  if (NULL != (p = strstr (next, CONTENT_PFIX)))	    {	      *(p + LEN_CONTENT_PFIX) = '\0';	      return 0;	    }	  	  	  if (0 == size_remain)	    break;	  	  next = remain - LEN_CONTENT_PFIX;	}      else if (EINTR == errno)	continue;      else	break;    }    fprintf (stderr, "Response is invailable.\n");  return -1;}int get_resource_info (char *const location){  struct url_http uh;  char *buf;   const size_t size_buf = 2048;    char *url;   struct sockaddr_in sockaddr_server;  char *p;  int fd_sock;  int retval = -1;  unsigned long int redirect = 0;    /* alloc memory. */  if (NULL == (buf = (char *) calloc (1, size_buf)))    {      fprintf (stderr, "Alloc memory failure.\n");      goto __FUNCTION__return;    }  url = location;    /* get the size and location of resource. */__FUNCTION__redirect:        if (-1 == parse_url_http (&uh, url))    return -1;    if (-1 == setup_sockaddr (&sockaddr_server, &uh))    goto __FUNCTION__free_buffer;        if (-1 == (fd_sock = send_request_head_file (&sockaddr_server, &uh)))    goto __FUNCTION__free_buffer;    if (-1 == recv_response_head_file (fd_sock, buf, size_buf))    goto __FUNCTION__close_fd_connect;  *(buf + size_buf - 1) = '\0';    if ((0 == strncmp (buf, RES_OK_1_0, LEN_HTTP_RES)) ||	\      (0 == strncmp (buf, RES_OK_1_1, LEN_HTTP_RES)))    {      if (-1 == get_resource_size (buf))	goto __FUNCTION__close_fd_connect;            resource.sockaddr.sin_family = sockaddr_server.sin_family;      resource.sockaddr.sin_port = sockaddr_server.sin_port;      resource.sockaddr.sin_addr = sockaddr_server.sin_addr;            strncpy (resource.path, uh.path, uh.len_path);      *(resource.path + uh.len_path) = '\0';      resource.len_path = uh.len_path;      retval = 0;      goto __FUNCTION__close_fd_connect;          }  else if ((0 == strncmp (buf, RES_RED_1_0, LEN_HTTP_RES)) ||	\	   (0 == strncmp (buf, RES_RED_1_1, LEN_HTTP_RES)))    {      redirect++;      if (0 == redirect)	{	  if (NULL == (url = calloc (1, (MAX_LEN_URL_HTTP + 8))))	    {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -