示例#1
0
文件: http.c 项目: pandagxnu/snarf
int
http_transfer(UrlResource *rsrc)
{
        FILE *out 		= NULL;
        Url *u			= NULL;
        Url *proxy_url		= NULL;
        Url *redir_u		= NULL;
        char *request		= NULL;
        char *raw_header	= NULL;
        HttpHeader *header	= NULL;
        char *len_string 	= NULL;
        char *new_location	= NULL;
        char buf[BUFSIZE];
        int sock 		= 0;
        ssize_t bytes_read	= 0;
        int retval		= 0;
        int i;

        /* make sure we haven't recursed too much */

        if( redirect_count > REDIRECT_MAX ) {
                report(ERR, "redirection max count exceeded " 
                      "(looping redirect?)");
                redirect_count = 0;
                return 0;
        }


        /* make sure everything's initialized to something useful */
        u = rsrc->url;
     
        if( ! *(u->host) ) {
                report(ERR, "no host specified");
                return 0;
        }

        /* fill in proxyness */
        if( !rsrc->proxy ) {
                rsrc->proxy = get_proxy("HTTP_PROXY");
        }

        if( !rsrc->outfile ) {
                if( u->file ) 
                        rsrc->outfile = strdup(u->file);
                else
                        rsrc->outfile = strdup("index.html");
        }

        if( !u->path )
                u->path = strdup("/");

        if( !u->file )
                u->file = strdup("");  /* funny looking */

        if( !u->port )
                u->port = 80;

        rsrc->options |= default_opts;
                
        /* send the request to either the proxy or the remote host */
        if( rsrc->proxy ) {
                proxy_url = url_new();
                url_init(proxy_url, rsrc->proxy);
                
                if( !proxy_url->port ) 
                        proxy_url->port = 80;

                if( !proxy_url->host ) {
                        report(ERR, "bad proxy `%s'", rsrc->proxy);
                        return 0;
                }

                if( proxy_url->username )
                        rsrc->proxy_username = strdup(proxy_url->username);

                if( proxy_url->password )
                        rsrc->proxy_password = strdup(proxy_url->password);

                /* Prompt for proxy password if not specified */
                if( proxy_url->username && !proxy_url->password ) {
                        char *prompt = NULL;
                        prompt = strconcat("Password for proxy ",
                                           proxy_url->username, "@",
                                           proxy_url->host, ": ", NULL);
                        proxy_url->password = strdup(getpass(prompt));
                        free(prompt);
                }

                if( ! (sock = tcp_connect(proxy_url->host, proxy_url->port)) )
                        return 0;


                u->path = strdup("");
                u->file = strdup(u->full_url);
                request = get_request(rsrc);

                write(sock, request, strlen(request));

        } else /* no proxy */ {

                if( ! (sock = tcp_connect(u->host, u->port)) )
                        return 0;

                request = get_request(rsrc);
                write(sock, request, strlen(request));
        }

        
        out = open_outfile(rsrc);
        if( !out ) {
                report(ERR, "opening %s: %s", rsrc->outfile, strerror(errno));
                return 0;
        }

        /* check to see if it returned a HTTP 1.x response */
        memset(buf, '\0', 5);

        bytes_read = read(sock, buf, 8);

        if( bytes_read == 0 ) {
                close(sock);
                return 0;
        }

        if( ! (buf[0] == 'H' && buf[1] == 'T' 
               && buf[2] == 'T' && buf[3] == 'P') ) {
                if ((rsrc->options & OPT_RESUME) && 
                    rsrc->outfile_offset) {
                        report(WARN,
                               "server does not support resume, "
                               "try again"
                               " with -n (no resume)");
                        retval = 0;
                        goto cleanup;
                }
                write(fileno(out), buf, bytes_read);
        } else {
                /* skip the header */
                buf[bytes_read] = '\0';
                raw_header = get_raw_header(sock);
                raw_header = strconcat(buf, raw_header, NULL);
                header = make_http_header(raw_header);

                if (rsrc->options & OPT_VERBOSE) {
                        fwrite(raw_header, 1, strlen(raw_header), stderr);
                }


                /* check for redirects */
                new_location = get_header_value("location", header);

                if (raw_header[9] == '3' && new_location ) {
                        redir_u = url_new();
                        
                        /* make sure we still send user/password along */
                        redir_u->username = safe_strdup(u->username);
                        redir_u->password = safe_strdup(u->password);

                        url_init(redir_u, new_location);
                        rsrc->url = redir_u;
                        redirect_count++;
                        retval = transfer(rsrc);
                        goto cleanup;
                }

                if (raw_header[9] == '4' || raw_header[9] == '5') {
                        for(i = 0; raw_header[i] && raw_header[i] != '\n'; i++);
                        raw_header[i] = '\0';
                        report(ERR, "HTTP error from server: %s", raw_header);
                        retval = 0;
                        goto cleanup;
                }
                        
                len_string = get_header_value("content-length", header);

                if (len_string)
                        rsrc->outfile_size = (off_t )atoi(len_string);

                if (get_header_value("content-range", header))
                        rsrc->outfile_size += rsrc->outfile_offset;

                if( (!rsrc->outfile_size) && 
                    (rsrc->options & OPT_RESUME) && 
                    !(rsrc->options & OPT_NORESUME)
                    && rsrc->outfile_offset ) {
                        report(WARN,
                             "unable to determine remote file size, try again"
                             " with -n (no resume)");
                        retval = 0;
                        goto cleanup;
                }
        }

        if( ! dump_data(rsrc, sock, out) )
                retval = 0;
        else
                retval = 1;
                        
 cleanup:
        free_http_header(header);
        close(sock); fclose(out);
        return retval;

}
示例#2
0
int http_transfer(UrlResource *rsrc, libnet_callback notify)
{
	FILE *out 		= NULL;
	Url *u			= NULL;
	Url *proxy_url		= NULL;
	Url *redir_u		= NULL;
	char *request		= NULL;
	//char *raw_header	= NULL;
	HttpHeader *header	= NULL;
	//char *len_string 	= NULL;
	//char *new_location	= NULL;
    char *tmp_string    = NULL;
	//char buf[BUFSIZE];
	int sock 		= -1;
	ssize_t bytes_read	= 0;
    int msg_code    = 0;
	int retval		= 0;
	int i;

    char *buf = MALLOC(BUFSIZE);
    if (!buf)
    {
        LIBNET_DEBUG("No enough memory!\n");
        return 0;
    }
	/* make sure we haven't recursed too much */
	if ( redirect_count > REDIRECT_MAX )
	{
		LIBNET_DEBUG("redirection max count exceeded (looping redirect?)");
		redirect_count = 0;
        msg_code = -NET_ERR_CONNECT_FAILED;
        goto cleanup;
	}


	/* make sure everything's initialized to something useful */
	u = rsrc->url;
	if ( !u->host )
	{
		LIBNET_DEBUG("no host specified");
        msg_code = -NET_ERR_CONNECT_FAILED;
        goto cleanup;
	}

	/* fill in proxyness */
	if ( !rsrc->proxy )
	{
		rsrc->proxy = get_proxy("HTTP_PROXY");
	}

	if (( NULL == rsrc->outfile ) && (NULL == rsrc->buffer))
	{
		if ( u->file )
			rsrc->outfile = strdup(u->file);
		else
			rsrc->outfile = strdup("index.html");
	}

	if ( !u->path )
		u->path = strdup("/");

	if ( !u->file )
		u->file = strdup("");  /* funny looking */

	if ( !u->port )
		u->port = 80;

	rsrc->options |= default_opts;

	/* send the request to either the proxy or the remote host */
	if ( rsrc->proxy )
	{
		proxy_url = url_new();
		url_init(proxy_url, rsrc->proxy);

		if ( !proxy_url->port )
			proxy_url->port = 80;

		if ( !proxy_url->host )
		{
			LIBNET_DEBUG( "bad proxy `%s'", rsrc->proxy);
            msg_code = -NET_ERR_CONNECT_FAILED;
            goto cleanup;
		}

		if ( proxy_url->username )
			rsrc->proxy_username = strdup(proxy_url->username);
		if ( proxy_url->password )
			rsrc->proxy_password = strdup(proxy_url->password);

#ifdef LIB_W5300
		sock = w5300_tcp_connect(proxy_url->host, proxy_url->port, rsrc->srcip, rsrc->srcport);		
#else
		sock = util_tcp_connect(proxy_url->host, proxy_url->port);
#endif
		if (sock < 0)
		{
            msg_code = -NET_ERR_CONNECT_FAILED;
            goto cleanup;            
		}

		safe_free(u->path);
		safe_free(u->file);
		u->path = strdup("");
		u->file = strdup(u->full_url);
		request = get_request(rsrc);
        LIBNET_DEBUG("sending request:\n%s", request);
		S_WRITE(sock, request, STRLEN(request));

		FREE(request);
	}
	else /* no proxy */
	{
#ifdef LIB_W5300
		sock = w5300_tcp_connect(u->host, u->port, rsrc->srcip, rsrc->srcport);		
#else
		sock = util_tcp_connect(u->host, u->port);
#endif
		if (sock < 0)
		{
            msg_code = -NET_ERR_CONNECT_FAILED;
            goto cleanup;            
		}
		request = get_request(rsrc);
        LIBNET_DEBUG("sending request:\n%s", request);
		S_WRITE(sock, request, STRLEN(request));

		FREE(request);
	}

	if (rsrc->outfile)
	{
		if ((get_file_size(rsrc->outfile) > 0) && (rsrc->options & OPT_RESUME))
			out = fopen(rsrc->outfile, "rb+");
		else
			out = fopen(rsrc->outfile, "wb");

		if ( !out )
		{
			LIBNET_DEBUG( "opening %s: %s", rsrc->outfile, "");			
            msg_code = -NET_ERR_FILE_SAVE_ERROR;
            goto cleanup;
			
		}
	}

	/* check to see if it returned a HTTP 1.x response */
	MEMSET(buf, '\0', 5);

#ifdef LIB_W5300
	bytes_read = S_READ(sock, buf, BUFSIZE);
    buf[bytes_read] = '\0';
    LIBNET_DEBUG("receive respond:(%d)\n%s", bytes_read, buf);
#else
	bytes_read = S_READ(sock, buf, 8);
#endif

	if ( bytes_read <= 0 )
	{
        msg_code = -NET_ERR_HTTP_SERVER_ERROR;
        goto cleanup;
	}

	if ( ! (buf[0] == 'H' && buf[1] == 'T'
			&& buf[2] == 'T' && buf[3] == 'P') )
	{
		if((rsrc->options & OPT_RESUME) &&	rsrc->outfile_offset)
		{
			LIBNET_DEBUG("server does not support resume!");
            msg_code = -NET_ERR_OPERATION_NOT_PERMIT;
			goto cleanup;
		}
		//fwrite(buf, bytes_read, 1,out);
	}
	else
	{
		/* skip the header */
#ifdef LIB_W5300
        buf[bytes_read] = '\0';
#else
		char *raw_header1 = NULL;
		buf[bytes_read] = '\0';
		raw_header1 = get_raw_header(sock);
		strconcat2(buf, raw_header1, NULL);
		FREE(raw_header1);
        LIBNET_DEBUG("receive respond:(%d)\n%s", bytes_read, buf);
#endif
		header = make_http_header(buf);

		/* check for redirects */
		tmp_string = get_header_value("location", header);

		if (buf[9] == '3' && tmp_string )
		{
#if 1			//diable redirec function
			redir_u = url_new();

			/* make sure we still send user/password along */
			redir_u->username = safe_strdup(u->username);
			redir_u->password = safe_strdup(u->password);

			url_init(redir_u, tmp_string);
			rsrc->url = redir_u;
			redirect_count++;
			//retval = transfer(rsrc, notify);
			transfer((UINT32)rsrc, (UINT32)notify);
			rsrc->url =u;
			redirect_count--;
			if(redirect_count<0) redirect_count=0;
			if (redir_u)
			{
				url_destroy(redir_u);
				FREE(redir_u);
			}
#endif			
            FREE(tmp_string);
            tmp_string = NULL;
            //msg_code = -NET_ERR_OPERATION_NOT_PERMIT;//we can support redirect now, remove this line.
			goto cleanup;
		}
        if (tmp_string)
        {
            FREE(tmp_string);
            tmp_string = NULL;
        }

		if (buf[9] == '4' || buf[9] == '5')
		{
			for (i = 0; buf[i] && buf[i] != '\n'; i++);
			buf[i] = '\0';
			LIBNET_DEBUG("HTTP error from server: %s\n", buf);

			if( buf[9] == '4' && buf[10] == '0' && buf[11] == '4') 
				msg_code = -NET_ERR_FILE_NOT_FOUND;
			else
				msg_code = -NET_ERR_HTTP_SERVER_ERROR;
			
			goto cleanup;
		}

		tmp_string = get_header_value("content-length", header);

		if (tmp_string)
		{
			rsrc->outfile_size = (off_t )ATOI(tmp_string);
	            FREE(tmp_string);
	            tmp_string = NULL;		
			if(rsrc->use_pecache ==0)
			{
				if ((rsrc->buffer) && (rsrc->buffer_len < rsrc->outfile_size))
				{
					LIBNET_DEBUG("the buffer length less than the file fize (%d < %d)\n", rsrc->buffer, (int)rsrc->outfile_size);
				    msg_code = -NET_ERR_FILE_SAVE_ERROR;
					goto cleanup;
				}
			}				
		}

        tmp_string = get_header_value("content-range", header);
		if (tmp_string)
		{
            FREE(tmp_string);
            tmp_string = NULL;
			rsrc->outfile_size += rsrc->outfile_offset;
		}

		if ((!rsrc->outfile_size) &&
				(rsrc->options & OPT_RESUME) &&
				!(rsrc->options & OPT_NORESUME)
				&& rsrc->outfile_offset )
		{
			LIBNET_DEBUG("unable to determine remote file size");
            msg_code = -NET_ERR_FILE_SAVE_ERROR;
			goto cleanup;
		}
	}

if(rsrc->use_pecache ==0)
	retval = dump_data(rsrc, sock, out, notify);
else
	retval = dump_data_to_pecache(rsrc, sock, out, notify);

cleanup:
	free_http_header(header);

    //if (raw_header)
	//	FREE(raw_header);
		

	if (proxy_url)
	{
		url_destroy(proxy_url);
		FREE(proxy_url);
	}

    if (sock >= 0)
    {
	    S_CLOSE(sock);
    }

	if (out)
		fclose(out);

    if (buf)
    {
        FREE(buf);
    }

#ifndef WIN32
	if (rsrc->outfile)
		fs_sync(rsrc->outfile);
#endif

    if (msg_code < 0 && rsrc->running)
    { 
		notify(NET_MSG_DOWNLOAD_FINISH, (UINT32)msg_code);
		libnet_abort_url_read(TRUE);//to break url_open while loop //retval!=1 means transfer fail
    }

	return retval;

}