4
#include <winsock2.h>
#include <windows.h>
#include <iostream>
#pragma comment(lib,"ws2_32.lib")
using namespace std;
int main (){
    WSADATA wsaData;
    if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0) {
        cout << "WSAStartup failed.\n";
        system("pause");
        return 1;
    }
    SOCKET Socket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
    struct hostent *host;
    host = gethostbyname("127.0.0.1");
    SOCKADDR_IN SockAddr;
    SockAddr.sin_port=htons(80);
    SockAddr.sin_family=AF_INET;
    SockAddr.sin_addr.s_addr = *((unsigned long*)host->h_addr);
    cout << "Connecting...\n";
    if(connect(Socket,(SOCKADDR*)(&SockAddr),sizeof(SockAddr)) != 0){
        cout << "Could not connect";
        system("pause");
        return 1;
    }
    cout << "Connected.\n";



          char header[]="POST /xampp/tests/file/check.php HTTP/1.1\r\n"
              "Host: 127.0.0.1\r\n"
              "Content-Type: application/x-www-form-urlencoded\r\n"
              "Content-Length: 10\r\n"
              "Connection: close\r\n"
              "\r\n"
              "text1=sase";
    send(Socket,header, strlen(header),0);
    char buffer[100000];
    int nDataLength;
    while ((nDataLength = recv(Socket,buffer,100000,0)) > 0){        
        int i = 0;
        while (buffer[i] >= 32 || buffer[i] == '\n' || buffer[i] == '\r') {
            cout << buffer[i];
            i += 1;
        }
    }
    closesocket(Socket);
        WSACleanup();
        cout<<endl<<endl;
    system("pause");
    return 0;
}

This is my current code. It sends text1, but now i want it to send a file (located in: C:\Users\Wade\Downloads\Documents) along with it. How do i do that how do i send a file from the user to a server using HTTP POST protocol

2
  • 1
    If you managed to send text, what's stopping you from converting the file to text (in binary mode) and send it the same way? I mean - you've already done the hard part, now it's time to do the standard things - reading files. Commented Sep 27, 2014 at 3:12
  • Any reason you're not using libcurl, curl.haxx.se. It's designed to do exactly what you want, and is a very robust, mature product. Commented Sep 27, 2014 at 3:39

3 Answers 3

6

application/x-www-form-urlencoded only supports name=value pairs. To POST a file, you have to either:

  1. Use multipart/form-data instead.

    char *header="POST /xampp/tests/file/check.php HTTP/1.1\r\n"
          "Host: 127.0.0.1\r\n"
          "Content-Type: multipart/form-data; boundary=myboundary\r\n"
          "Connection: close\r\n"
          "\r\n"
          "--myboundary\r\n"
          "Content-Type: application/octet-stream\r\n"
          "Content-Disposition: form-data; name=\"myfile\"; filename=\"myfile.ext\"\r\n"
          "Content-Transfer-Encoding: 8bit\r\n"
          "\r\n";
    send(Socket,header, strlen(header),0);
    
    // send the raw file bytes here...
    
    char *footer = "\r\n"
               "--myboundary--\r\n";
    send(Socket, footer, strlen(footer), 0);
    
  2. Send the content of the file by itself as the entire POST content, set the Content-Type to the actual type of the file or application/octet-stream, and set the Content-Length to the size of the file.

    char *header="POST /xampp/tests/file/check.php HTTP/1.1\r\n"
          "Host: 127.0.0.1\r\n"
          "Content-Type: application/octet-stream\r\n"
          "Content-Length: ...\r\n" // <-- substitute with the actual file size
          "Connection: close\r\n"
          "\r\n";
    send(Socket,header, strlen(header),0);
    
    // send the raw file bytes here...
    

Which one you use depends on what the server is capable of accepting.

Sign up to request clarification or add additional context in comments.

4 Comments

how do i send raw file bytes?
Open the file (CreateFile() or fopen()) and loop through it reading its data (ReadFile() or fread()) into a fixed-sized buffer that you send() on each loop iteration until you reach EOF. Or use TransmitFile().
ive noticed the multipart/form-data doesnt have a Content-Length was that on purpose
Yes. multipart/... types are defined by MIME, and MIME does not rely on Content-Length. Data is delimited by unique boundary markers instead.
1

use this codes

#define DATA_SIZE 1024*1024*10 //10MB
#define MAXLINE 409600

char * servIP = "127.0.0.1";
int servPort = 80;

ssize_t send_file(char *fileDir, char *filename)
{
    char *packet;
    char pre_body[1024], post_body[1024];
    char sendline[MAXLINE + 1];
    char boundary[] ="----WebKitFormBoundaryu8FzpUGNDgydoA4z";

    char *bodyline = calloc(sizeof(char), DATA_SIZE);
    char *fileBuf = calloc(sizeof(char), DATA_SIZE);
    int sock = makeSocket();

    printf("send file name : %s\n", filename);

    FILE *fp = fopen(fileDir, "r");
    if(fp == NULL){
        printf("file can't read\n");
        fclose(fp);
        return -1;
    }

    fseek(fp, 0, SEEK_END);
    int file_size = ftell(fp);
    fseek(fp, 0, SEEK_SET);
    if(fread(fileBuf, 1, file_size, fp) == -1){
        printf("fread error\n");
    }
    // make body
    sprintf(pre_body, "--%s\r\nContent-Disposition: form-data; name=\"pdata\"\r\n\r\n"
        "%s\r\n--%s\r\nContent-Disposition: form-data; name=\"flag\"\r\n\r\n"
        "%s\r\n--%s\r\nContent-Disposition: form-data; name=\"upfile\";filename=\"%s\"\r\n"
        "Content-Type:application/octect-stream\r\n\r\n"
        ,  boundary, "postdata", boundary,"no", boundary, filename);

    sprintf(post_body, "\r\n--%s--\r\n", boundary);

    int pre_len = strlen(pre_body);
    int post_len = strlen(post_body);
    int body_len = pre_len + file_size + post_len;

    memcpy(bodyline, pre_body, pre_len);
    memcpy(bodyline+pre_len, fileBuf, file_size);
    memcpy(bodyline+pre_len+file_size, post_body, post_len);

    //make header
    sprintf(sendline, "POST /FileUpload.jsp HTTP/1.1\r\n"
        "Host: %s\r\nConnection: keep-alive\r\n"
        "Content-Length: %d\r\n"
        "Content-Type: multipart/form-data; boundary=%s\r\n\r\n", servIP, body_len, boundary);
    int head_len = strlen(sendline);
    int packet_len = head_len+body_len;

    //join header + body
    packet=calloc(1, head_len+body_len+1);
    memcpy(packet, sendline, head_len);
    memcpy(packet+head_len, bodyline, body_len);


    write(sock, packet, packet_len);

    fclose(fp);
    free(packet);
    close(sock);
    return 0;
}

int makeSocket(){
    struct sockaddr_in servAddr;
    int sock;
    char ip[20];
    /* Create areliable, stream socket using TCP */
    if((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
        printf("socket create failed\n");

    struct hostent *host_entry;
    host_entry = gethostbyname(servIP);
    for(ndx = 0; NULL != host_entry->h_addr_list[ndx]; ndx++){
        strcpy(ip, inet_ntoa(*(struct in_addr*)host_entry->h_addr_list[ndx]));
    }

    memset(&servAddr, 0, sizeof(servAddr)); //Zero ou structure
    servAddr.sin_family = AF_INET; //Internet address family
    servAddr.sin_addr.s_addr = inet_addr(ip); //Server IP address
    servAddr.sin_port = htons(servPort);//Server port

    /* Establish the connection to the web server */
    if(connect(sock, (struct sockaddr *) &servAddr, sizeof(servAddr)) < 0)
            printf("connet() failed\n");

    return sock;
}

2 Comments

Please provide some description to point out what could have gone wrong. It will help the people to understand what was the mistake and help them learn rather than just providing the code.
Other codes failed for me, this one did the trick, I think the "Content-Length" was needed....
0

I go it to work. here's the code without reading the file.

char outtemp[];
     ifstream inFile("c:\\temp.html");
     ofstream outtemp("temp");
     while(inFile.good()){
                          getline(inFile,buffer);
                          outtemp<<buffer;
                          }
     inFile.close();//close files after using
     outtemp.close();//close files after using




    char data[]=
    "\r\n"
    "--border287032381131322\r\n"
    "Content-Disposition: form-data; name=\"this\" \r\n\r\n" 
    "aasda\r\n\r\n"
    "--border287032381131322\r\n"
    "Content-Disposition: form-data; name=\"file\"; filename=\"C:\\temp.html\" Content-Type: text/plain \r\n\r\n" 
char data2[]=
    "<h1>Home page on main server</h1>\r\n\r\n"
    "--border287032381131322--\r\n";

    char header[] =
    "POST /xampp/tests/winsock_test/do.php HTTP/1.1\r\n"
    "Host: 127.0.0.1\r\n"
    "Content-Type: multipart/form-data; boundary=border287032381131322\r\n"
    "Connection: close\r\n";
    strcat(header,data1);
strcat(header,outtemp);
strcat(header,data2)
    cout<<"----------Sending----------------"<<endl<<header<<endl<<"size:"<<sizeof(data)<<endl<<"--------------sending end------------"<<endl<<endl;// for debug

    send(Socket,header, strlen(header),0);

1 Comment

You don't need a Content-Length with multipart/form-data, and the filename attribute should not contain path information, only the filename. In any case, this does not answer your original question, because you specifically asked how to send a file from the user's file system, and this code is not doing that.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.