mirror of
				https://github.com/lxsang/antd-lua-plugin
				synced 2025-10-31 02:15:37 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			539 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			539 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| #include<stdio.h> //printf
 | |
| #include<string.h> //memset
 | |
| #include<stdlib.h> //for exit(0);
 | |
| #include<errno.h> //For errno - the error number
 | |
| #include<netdb.h> //hostent
 | |
| #include <netinet/in.h>
 | |
| #include <arpa/inet.h>
 | |
| //#include <signal.h>
 | |
| #include <dirent.h>
 | |
| #include <errno.h>
 | |
| #include <sys/socket.h>
 | |
| #include <resolv.h>
 | |
| #include <errno.h>
 | |
| #include <ifaddrs.h>
 | |
| #include <sys/stat.h>
 | |
| #include <libgen.h>
 | |
| 	
 | |
| #define CLIENT_NAME "wurl"
 | |
| #define CLIENT_HOST "192.168.9.249"
 | |
| #define CONN_TIME_OUT_S 3
 | |
| #define MAX_BUFF 1024
 | |
| #define REQUEST_BOUNDARY "------wURLFormBoundaryVo4QYVaSVseFNpeK"
 | |
| #define GET 0
 | |
| #define POST 1
 | |
| typedef struct{
 | |
| 	int type; 		// POST(1) or GET(0)
 | |
| 	char* resource;	// path
 | |
| 	char* ctype;	// content type, used by POST
 | |
| 	int clen;		// content length, used by POST
 | |
| 	unsigned char* data ;
 | |
| } wurl_header_t;
 | |
| 
 | |
| /*get the ip by hostname*/
 | |
| int wurl_ip_from_hostname(const char * hostname , char* ip)
 | |
| {
 | |
|     struct hostent *he;
 | |
|     struct in_addr **addr_list;
 | |
|     int i;    
 | |
|     if ( (he = gethostbyname( hostname ) ) == NULL) 
 | |
|     {
 | |
|         // get the host info
 | |
|         herror("gethostbyname");
 | |
|         return -1;
 | |
|     }
 | |
|     addr_list = (struct in_addr **) he->h_addr_list;
 | |
|      
 | |
|     for(i = 0; addr_list[i] != NULL; i++) 
 | |
|     {
 | |
|         //Return the first one;
 | |
|         strcpy(ip , inet_ntoa(*addr_list[i]) );
 | |
|         return 0;
 | |
|     }
 | |
|     return -1;
 | |
| }
 | |
| 
 | |
| /*
 | |
| send a request
 | |
| */
 | |
| int wurl_request_socket(const char* ip, int port)
 | |
| {
 | |
| 	int sockfd, bytes_read;
 | |
| 	struct sockaddr_in dest;
 | |
| 	
 | |
| 	// time out setting
 | |
| 	struct timeval timeout;      
 | |
| 	timeout.tv_sec = CONN_TIME_OUT_S;
 | |
| 	timeout.tv_usec = 0;
 | |
| 	if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0 )
 | |
| 	{
 | |
| 		perror("Socket");
 | |
| 		return -1;
 | |
| 	}
 | |
| 	if (setsockopt (sockfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout,sizeof(timeout)) < 0)
 | |
| 	        perror("setsockopt failed\n");
 | |
| 
 | |
|     if (setsockopt (sockfd, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout,sizeof(timeout)) < 0)
 | |
|         perror("setsockopt failed\n");
 | |
| 	
 | |
|     bzero(&dest, sizeof(dest));
 | |
|     dest.sin_family = AF_INET;
 | |
|     dest.sin_port = htons(port);
 | |
|     if ( inet_aton(ip, &dest.sin_addr.s_addr) == 0 )
 | |
|     {
 | |
| 		perror(ip);
 | |
| 		close(sockfd);
 | |
| 		return -1;
 | |
|     }
 | |
| 	if ( connect(sockfd, (struct sockaddr*)&dest, sizeof(dest)) != 0 )
 | |
| 	{
 | |
| 		close(sockfd);
 | |
| 		perror("Connect");
 | |
| 		return -1;
 | |
| 	}
 | |
| 	return sockfd;
 | |
| }
 | |
| /*
 | |
| POST %s HTTP/1.0\r\n
 | |
| Host: %s\r\n
 | |
| User-Agent: %s\r\n
 | |
| Content-Type: %s\r\n
 | |
| Content-Length: %d\r\n\r\n"
 | |
| 
 | |
| maybe cookie support? this can cause security problem
 | |
| 
 | |
| GET %s HTTP/1.0\r\n
 | |
| Host: %s\r\n
 | |
| User-Agent: %s\r\n\r\n"
 | |
| 
 | |
| multipart
 | |
| POST %s HTTP/1.1
 | |
| Host: %s
 | |
| User-Agent: %s
 | |
| Content-Type: multipart/form-data; boundary=----------287032381131322
 | |
| Content-Length: %d
 | |
| 
 | |
| ------------287032381131322
 | |
| Content-Disposition: form-data; name="datafile1"; filename="r.gif"
 | |
| Content-Type: image/gif
 | |
| 
 | |
| GIF87a.............,...........D..;
 | |
| ------------287032381131322
 | |
| Content-Disposition: form-data; name="datafile2"; filename="g.gif"
 | |
| Content-Type: image/gif
 | |
| 
 | |
| GIF87a.............,...........D..;
 | |
| ------------287032381131322
 | |
| Content-Disposition: form-data; name="datafile3"; filename="b.gif"
 | |
| Content-Type: image/gif
 | |
| 
 | |
| GIF87a.............,...........D..;
 | |
| ------------287032381131322--
 | |
| */
 | |
| 
 | |
| int wurl_header(int sockfd, wurl_header_t rq)
 | |
| {	
 | |
| 	char buff[MAX_BUFF];
 | |
| 	if(sockfd < 0) return -1;
 | |
| 	
 | |
| 	if(rq.type == GET)  // GET
 | |
| 	{
 | |
| 		send(sockfd,"GET ",4,0);
 | |
| 		send(sockfd,rq.resource, strlen(rq.resource),0);
 | |
| 		send(sockfd," HTTP/1.0\r\n",11,0);
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		send(sockfd,"POST ",5, 0);
 | |
| 		send(sockfd,rq.resource, strlen(rq.resource),0);
 | |
| 		send(sockfd," HTTP/1.0\r\n",11,0);
 | |
| 		sprintf(buff,"Content-Type: %s\r\n", rq.ctype);
 | |
| 		send(sockfd,buff,strlen(buff),0);
 | |
| 		sprintf(buff,"Content-Length: %d\r\n", rq.clen);
 | |
| 		send(sockfd,buff,strlen(buff),0);
 | |
| 	}
 | |
| 	// host dont need to send the host
 | |
| 	//sprintf(buff,"Host: %s\r\n",CLIENT_HOST);
 | |
| 	//send(sockfd,buff,strlen(buff),0);
 | |
| 	// user agent
 | |
| 	sprintf(buff,"User-Agent: %s\r\n",CLIENT_NAME);
 | |
| 	send(sockfd,buff,strlen(buff),0);
 | |
| 	// terminate  request
 | |
| 	send(sockfd,"\r\n",2,0);
 | |
| 
 | |
| 	// if there is data, send out
 | |
| 	if(rq.type == POST && rq.data)
 | |
| 	{
 | |
| 		send(sockfd,rq.data,rq.clen,0);
 | |
| 	}
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| 
 | |
| // this will be removed
 | |
| #define IEQU(a,b) (strcasecmp(a,b) == 0)
 | |
| #define LOG(x) printf(x)
 | |
| /**
 | |
|  * Trim a string by a character on both ends
 | |
|  * @param str   The target string
 | |
|  * @param delim the delim
 | |
|  */
 | |
| void trim(char* str, const char delim)
 | |
| {
 | |
|     char * p = str;
 | |
|     int l = strlen(p);
 | |
| 
 | |
|     while(p[l - 1] == delim) p[--l] = 0;
 | |
|     while(* p && (* p) == delim ) ++p, --l;
 | |
|     memmove(str, p, l + 1);
 | |
| }
 | |
| /**
 | |
|  * Get extension of a file name
 | |
|  * @param  file The file name
 | |
|  * @return      the extension
 | |
|  */
 | |
| char* ext(const char* file)
 | |
| {
 | |
| 	char* token,*ltoken = "";
 | |
| 	if(file == NULL) return NULL;
 | |
| 	char* str_cpy = strdup(file);
 | |
| 	if(strstr(str_cpy,".")<= 0) return "";
 | |
| 	if(*file == '.')
 | |
| 		file++;
 | |
| 
 | |
| 	while((token = strsep(&str_cpy,".")) && strlen(token)>0) {ltoken = token;}
 | |
| 	free(str_cpy);
 | |
| 	return ltoken;
 | |
| 
 | |
| }
 | |
| /**
 | |
|  * Get correct HTTP mime type of a file
 | |
|  * This is a minimalistic mime type list supported
 | |
|  * by the server
 | |
|  * @param  file File name
 | |
|  * @return      The HTTP Mime Type
 | |
|  */
 | |
| char* mime(const char* file)
 | |
| {
 | |
| 	char * ex = ext(file);
 | |
| 	if(IEQU(ex,"bmp"))
 | |
| 		return "image/bmp";
 | |
| 	else if(IEQU(ex,"jpg") || IEQU(ex,"jpeg"))
 | |
| 		return "image/jpeg";
 | |
| 	else if(IEQU(ex,"css"))
 | |
| 		return "text/css";
 | |
| 	else if(IEQU(ex,"csv"))
 | |
| 		return "text/csv";
 | |
| 	else if(IEQU(ex,"pdf"))
 | |
| 		return "application/pdf";
 | |
| 	else if(IEQU(ex,"gif"))
 | |
| 		return "image/gif";
 | |
| 	else if(IEQU(ex,"html")||(IEQU(ex,"htm")))
 | |
| 		return "text/html";
 | |
| 	else if(IEQU(ex,"json"))
 | |
| 		return "application/json";
 | |
| 	else if(IEQU(ex,"js"))
 | |
| 		return "application/javascript";
 | |
| 	else if(IEQU(ex,"png"))
 | |
| 		return "image/png";
 | |
| 	else if(IEQU(ex,"ppm"))
 | |
| 		return "image/x-portable-pixmap";
 | |
| 	else if(IEQU(ex,"rar"))
 | |
| 		return "application/x-rar-compressed";
 | |
| 	else if(IEQU(ex,"tiff"))
 | |
| 		return "image/tiff";
 | |
| 	else if(IEQU(ex,"tar"))
 | |
| 		return "application/x-tar";
 | |
| 	else if(IEQU(ex,"txt"))
 | |
| 		return "text/plain";
 | |
| 	else if(IEQU(ex,"ttf"))
 | |
| 		return "application/x-font-ttf";
 | |
| 	else if(IEQU(ex,"xhtml"))
 | |
| 		return "application/xhtml+xml";
 | |
| 	else if(IEQU(ex,"xml"))
 | |
| 		return "application/xml";
 | |
| 	else if(IEQU(ex,"zip"))
 | |
| 		return "application/zip";
 | |
| 	else if(IEQU(ex,"svg"))
 | |
| 		return "image/svg+xml";
 | |
| 	else if(IEQU(ex,"eot"))
 | |
| 		return "application/vnd.ms-fontobject";
 | |
| 	else if(IEQU(ex,"woff") || IEQU(ex,"woff2"))
 | |
| 		return "application/x-font-woff";
 | |
| 	else if(IEQU(ex,"otf"))
 | |
| 		return "application/x-font-otf";
 | |
| 	//audio
 | |
| 	else if(IEQU(ex,"mp3"))
 | |
| 		return "audio/mpeg";
 | |
| 	else 
 | |
| 		// The other type will be undestant as binary
 | |
| 		return "application/octet-stream";
 | |
| }
 | |
| 
 | |
| void wurl_send_files(int sockfd,char* resource, int n, char* name [], char* files[])
 | |
| {
 | |
| 	char buff[MAX_BUFF];
 | |
| 	wurl_header_t rq;
 | |
| 	rq.type = POST;
 | |
| 	rq.resource = resource;
 | |
| 	// get the total size of data
 | |
| 	int totalsize = 0;
 | |
| 	FILE* fd;
 | |
| 	struct stat st;
 | |
| 	for(int i = 0; i < n; ++i)
 | |
| 	{
 | |
| 		if(stat(files[i], &st) != 0) continue;
 | |
| 		totalsize += st.st_size;
 | |
| 	}
 | |
| 	rq.clen = totalsize;
 | |
| 	sprintf(buff,"%s; boundary=%s","multipart/form-data",REQUEST_BOUNDARY);
 | |
| 	rq.ctype = buff;
 | |
| 	
 | |
| 	// now send the header
 | |
| 	wurl_header(sockfd,rq);
 | |
| 	// now send the files
 | |
| 	size_t size;
 | |
| 	for(int i = 0; i < n; ++i)
 | |
| 	{
 | |
| 		fd = fopen(files[i],"rb");
 | |
| 		if(!fd) continue;
 | |
| 		// first send the boundary
 | |
| 		sprintf(buff,"%s\r\n",REQUEST_BOUNDARY);
 | |
| 		send(sockfd, buff, strlen(buff),0);
 | |
| 		// content disposition
 | |
| 		sprintf(buff,"Content-Disposition: form-data; name=\"%s\"; filename=\"%s\"\r\n",
 | |
| 					name[i],basename(files[i]));
 | |
| 		send(sockfd,buff, strlen(buff),0);
 | |
| 		// content type
 | |
| 		sprintf(buff,"Content-Type: %s\r\n\r\n",mime(files[i]));
 | |
| 		send(sockfd,buff, strlen(buff),0);
 | |
| 		// now send the file
 | |
| 		while(!feof(fd))
 | |
| 		{
 | |
| 			size = fread(buff,1,MAX_BUFF,fd);
 | |
| 			send(sockfd,buff,size,0);
 | |
| 			//if(!__b(client,buffer,size)) return;
 | |
| 		}
 | |
| 		fclose(fd);
 | |
| 		send(sockfd,"\r\n",2,0);
 | |
| 	}
 | |
| 	//end the boudary
 | |
| 	sprintf(buff,"%s--\n",REQUEST_BOUNDARY);
 | |
| 	send(sockfd,buff,strlen(buff),0);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Read the socket request in to a buffer or size
 | |
|  * The data is read until the buffer is full or
 | |
|  * there are a carrier return character
 | |
|  * @param  sock socket
 | |
|  * @param  buf  buffer
 | |
|  * @param  size size of buffer
 | |
|  * @return      number of bytes read
 | |
|  */
 | |
| int wurl_read_buf(int sock, char*buf,int size)
 | |
| {
 | |
| 	int i = 0;
 | |
| 	char c = '\0';
 | |
| 	int n;
 | |
| 	while ((i < size - 1) && (c != '\n'))
 | |
| 	{
 | |
| 		n = recv(sock, &c, 1, 0);
 | |
| 		if (n > 0)
 | |
| 		{
 | |
| 			buf[i] = c;
 | |
| 			i++;
 | |
| 		}
 | |
| 		else
 | |
| 			c = '\n';
 | |
| 	}
 | |
| 	buf[i] = '\0';
 | |
| 	return i;
 | |
| }
 | |
| /*
 | |
| 	POST example
 | |
| 	wurl_header_t rq;
 | |
| 	rq.resource = path;
 | |
| 	rq.type = POST;
 | |
| 	rq.data = "s=a&q=b#test";//"{\"name\":\"sang\"}";
 | |
| 	rq.clen =  strlen(rq.data);
 | |
| 	rq.ctype = "application/x-www-form-urlencoded";//"application/json";
 | |
| 	
 | |
| 	if(wurl_request(hostname,port,&rq,1) == 0)
 | |
| 	{
 | |
| 		printf(rq.data);
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		printf("Cannot connect to host\n");
 | |
| 	}
 | |
| 	
 | |
| 	DOWNLOAD
 | |
| 	wurl_header_t rq;
 | |
| 	rq.resource = path;
 | |
| 	rq.type = GET;
 | |
| 	
 | |
| 	if(wurl_download(hostname,port,&rq,file) == 0)
 | |
| 	{
 | |
| 		printf("Download sucess ful\n");
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		printf("Cannot connect to host\n");
 | |
| 	}
 | |
| 
 | |
| 	
 | |
| 	upload example
 | |
| 		// send files
 | |
| 		char * names[2];
 | |
| 		names[0] = "zip";
 | |
| 		names[1] = "text";
 | |
| 		char* files[2];
 | |
| 		files[0] = "/Users/mrsang/tmp/Archive.zip";
 | |
| 		files[1] = "/Users/mrsang/tmp/test.py";
 | |
| 		
 | |
| 		wurl_send_files(sock,path,2,names, files);
 | |
| 		printf("RETURN:\n");
 | |
| 		size = wurl_read_buf(sock,buff, MAX_BUFF);
 | |
| 		while(size > 0)
 | |
| 		{
 | |
| 			printf("%s", buff);
 | |
| 			size = wurl_read_buf(sock,buff, MAX_BUFF);
 | |
| 		}
 | |
| 		close(sock);
 | |
| */
 | |
| 
 | |
| /*
 | |
| 	hostname
 | |
| 	port
 | |
| 	header for request and respond
 | |
| 	lazy : 	if 1, all data is read to the header
 | |
| 			if 0, user has the responsibility to handler it
 | |
| */
 | |
| int wurl_request(const char* hostname, int port, wurl_header_t* header, int lazy)
 | |
| {
 | |
| 	char ip[100];
 | |
| 	char buff[MAX_BUFF];
 | |
| 	wurl_ip_from_hostname(hostname ,ip);
 | |
| 	int sock = wurl_request_socket(ip, port);
 | |
| 	
 | |
| 	if(sock <= 0) return -1;
 | |
| 	// send header
 | |
| 	wurl_header(sock,*header);
 | |
| 	// read respond header
 | |
| 	int size  = wurl_read_buf(sock,buff,MAX_BUFF);
 | |
| 	char* token;
 | |
| 	while (size > 0 && strcmp("\r\n",buff))
 | |
| 	{
 | |
| 		char* line = strdup(buff);
 | |
| 		token = strsep(&line,":");
 | |
| 		trim(token,' ');
 | |
| 		if(token != NULL &&strcasecmp(token,"Content-Type") == 0)
 | |
| 		{
 | |
| 			header->ctype = strsep(&line,":");
 | |
| 			trim(header->ctype,' ');
 | |
| 			trim(header->ctype,'\n');
 | |
| 			trim(header->ctype,'\r');
 | |
| 		} else if(token != NULL &&strcasecmp(token,"Content-Length") == 0)
 | |
| 		{
 | |
| 			token = strsep(&line,":");
 | |
| 			trim(token,' ');
 | |
| 			header->clen = atoi(token);
 | |
| 		}
 | |
| 		//if(line) free(line);
 | |
| 		size  = wurl_read_buf(sock,buff,MAX_BUFF);
 | |
| 	}
 | |
| 	if(header->ctype == NULL || header->clen == -1)
 | |
| 	{
 | |
| 		LOG("Bad data\n");
 | |
| 		return -1;
 | |
| 	}
 | |
| 	
 | |
| 	// read data if lazy
 | |
| 	if(lazy)
 | |
| 	{
 | |
| 		// read line by line, ignore content length
 | |
| 		int total_length = 0;
 | |
| 		char* tmp = NULL;
 | |
| 		int CHUNK = 512;
 | |
| 		header->data = (unsigned char*) malloc(CHUNK);
 | |
| 		int cursize = CHUNK;
 | |
| 		int size = wurl_read_buf(sock,buff,MAX_BUFF);
 | |
| 		while(size > 0)
 | |
| 		{
 | |
| 			if(total_length+size > cursize)
 | |
| 			{
 | |
| 				tmp = (unsigned char*) realloc(header->data,total_length + size);
 | |
| 				if(!tmp) 
 | |
| 				{
 | |
| 					if(header->data) free(header->data);
 | |
| 					break;
 | |
| 				}
 | |
| 				header->data = tmp;
 | |
| 			}
 | |
| 			memcpy(header->data+total_length,buff,size);
 | |
| 			total_length += size;
 | |
| 			size = wurl_read_buf(sock,buff,MAX_BUFF);
 | |
| 		}
 | |
| 		header->clen = total_length;
 | |
| 		close(sock);
 | |
| 		return 0;
 | |
| 	} 	
 | |
| 	return sock;
 | |
| }
 | |
| 
 | |
| int wurl_download(const char* hostname, int port, wurl_header_t* h, const char* to)
 | |
| {
 | |
| 	// we will handler the data reading
 | |
| 	int sock = wurl_request(hostname, port,h,0);
 | |
| 	unsigned char buff[MAX_BUFF];
 | |
| 	if(sock < 0) return -1;
 | |
| 	
 | |
| 	FILE* fp =  fopen(to,"wb");
 | |
| 	int size;
 | |
| 	if(fp)
 | |
| 	{
 | |
| 		while((size = wurl_read_buf(sock,buff, MAX_BUFF)) > 0)
 | |
| 		{
 | |
| 			fwrite(buff, size, 1, fp);
 | |
| 		}
 | |
| 		fclose(fp);
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		close(sock);
 | |
| 		return -1;
 | |
| 	}
 | |
| 	close(sock);
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| int main (int argc, char const *argv[])
 | |
| {
 | |
| 	if(argc < 4)
 | |
| 	{
 | |
| 	        printf("wurl [host] [port] [path]\n");
 | |
| 	        exit(1);
 | |
| 	}
 | |
|      
 | |
| 	char *hostname = argv[1];
 | |
| 	char* path = argv[3];	
 | |
| 	int port = atoi(argv[2]);
 | |
| 	char*file = argv[4];
 | |
| 	wurl_header_t rq;
 | |
| 	rq.resource = path;
 | |
| 	rq.type = POST;
 | |
| 	rq.data = "s=a&q=b#test";//"{\"name\":\"sang\"}";
 | |
| 	rq.clen =  strlen(rq.data);
 | |
| 	rq.ctype = "application/x-www-form-urlencoded";//"application/json";
 | |
| 	
 | |
| 	if(wurl_download(hostname,port,&rq,file) == 0)
 | |
| 	{
 | |
| 		printf("Download sucess ful\n");
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		printf("Cannot connect to host\n");
 | |
| 	}
 | |
| 	return 0;
 | |
| } |