I have a C++ routine(client-side) which uploads an xml file to a web server by making a socket connection and sending all the post request through that socket.
On the server side I have a cgi script which receives all the data and creates a file in the specified directory.
If I am uploading only the file all works well, however I want to send data of other fields too (field1, field2 ..etc), this fails the post request and even the file is not uploaded.
I think it has something to do with the Boundary Strings that need to be sent with each part of the form-data.
However I am unable to understand how to do that.
Greatly appreciate any help.
Here is my code snippet for preparing the post request for sending the form-data
Expand|Select|Wrap|Line Numbers
- int Send_to_DB_via_HTTP(char* Traveller_output_buffer, unsigned data_len, string fileName, string servIP, string url)
- {
- int sock; /* Socket descriptor */
- struct sockaddr_in echoServAddr; /* server address */
- unsigned short echoServPort; /* server port */
- char *echoString; /* String to send to echo server */
- char echoBuffer[RCVBUFSIZE]; /* Buffer for echo string */
- unsigned int echoStringLen; /* Length of string to echo */
- int bytesRcvd, totalBytesRcvd; /* Bytes read in single recv()
- and total bytes read */
- int first_form_len=0;
- int second_form_len=0;
- int hidden_data_len=0;
- unsigned count = 0;
- int count1 = 0;
- int count2 = 0;
- char buf[2000];
- int n;
- const char *m_servIP;
- const char *m_url;
- m_servIP = servIP.c_str();
- m_url = url.c_str();
- echoServPort = 80;
- /*Create a reliable, stream socket using TCP */
- if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
- cout << " socket () failed" << endl;
- /* Construct the server address structure */
- memset(&echoServAddr, 0, sizeof(echoServAddr)); /* Zero out structure */
- echoServAddr.sin_family = PF_INET; /* Internet address family */
- echoServAddr.sin_addr.s_addr = inet_addr(m_servIP); /* Server IP address */
- echoServAddr.sin_port = htons(echoServPort); /* Server port */
- /* Establish the connection to the echo server */
- int k;
- k = connect(sock, (struct sockaddr *) &echoServAddr, sizeof(echoServAddr));
- if (k < 0)
- {
- cout<< "Error Connecting to " << servIP << endl;
- return -1;
- }
- else
- cout << "Connection Successfull to " << servIP << endl;
- //Start the form off with the boundary string
- hidden_data_len += snprintf(
- &Buffer3[hidden_data_len],
- sizeof(Buffer3) - hidden_data_len,
- "%s%s\r\n",
- "--", BOUNDARY_STRING);
- hidden_data_len += snprintf(
- &Buffer3[hidden_data_len],
- sizeof(Buffer3) - (hidden_data_len),
- "Content-Disposition: form-data;name=\"field1\"\r\n\r\n%s_auto_end\r\n",
- syssn_no );
- //End of multi-part form
- hidden_data_len += snprintf(
- &Buffer3[hidden_data_len],
- sizeof(Buffer3) - (hidden_data_len),
- "%s%s%s\r\n",
- "--",BOUNDARY_STRING,"--" );
- first_form_len += snprintf(
- &buffer1[first_form_len],
- sizeof(buffer1) - first_form_len,
- "%s%s\r\n",
- "--",BOUNDARY_STRING );
- //Some random filename - must end in .dat because web server checks
- //This is the data portion of the form - the flat file will be sent in this section
- first_form_len += snprintf(
- &buffer1[first_form_len],
- sizeof(buffer1) - first_form_len,
- "Content-Disposition: form-data; name=\"flat_file\"; filename=\"travellerdata.dat\"\r\n" );
- first_form_len += snprintf(
- &buffer1[first_form_len],
- sizeof(buffer1) - first_form_len,
- "Content-Type: text/plain\r\n\r\n" );
- //Prepare the ending part of the form-data - this follows the flat file contents
- //Start the form off with the boundary string
- /*second_form_len += snprintf(
- &buffer1[first_form_len+second_form_len],
- sizeof(buffer1) - (first_form_len+second_form_len),
- "%s%s\r\n",
- "--",BOUNDARY_STRING );*/
- // Put together the headers for HTTP POST
- count = snprintf(
- &buffer[0],
- sizeof(buffer),
- "POST %s HTTP/1.1\r\n",
- m_url);
- count += snprintf(
- &buffer[count],
- sizeof(buffer) - count,
- "Accept-Language: en-us\r\n" );
- count += snprintf(
- &buffer[count],
- sizeof(buffer) - count,
- "Content-Type: multipart/form-data; boundary=%s\r\n",
- BOUNDARY_STRING);
- count += snprintf(
- &buffer[count],
- sizeof(buffer) - count,
- "User-Agent: Mozilla/3.01 (compatible)\r\n");
- count += snprintf(
- &buffer[count],
- sizeof(buffer) - count,
- "Host: %s\r\n",
- m_servIP);
- count += snprintf(
- &buffer[count],
- sizeof(buffer) - count,
- "Pragma: no-cache\r\n" );
- count += snprintf(
- &buffer[count],
- sizeof(buffer) - count,
- "Content-Length: %d\r\n",
- data_len+first_form_len+second_form_len+hidden_data_len );
- count += snprintf(
- &buffer[count],
- sizeof(buffer) - count,
- "\r\n" );
- //cout << buffer << endl;
- count1 += snprintf(
- &buffer2[count1],
- sizeof(buffer2) - count1,
- "%s%s\r\n",
- "--",BOUNDARY_STRING);
- count1 += snprintf(
- &buffer2[count1],
- sizeof(buffer2) - count1,
- "Content-Disposition: form-data; \"\r\n");
- count1 += snprintf(
- &buffer2[count1],
- sizeof(buffer2) - count1,
- "Content-Type: text/html\r\n");
- count1 += snprintf(
- &buffer2[count1],
- sizeof(buffer2) - count1,
- "Content-Length: %d\r\n", data_len);
- count2 += snprintf(
- &buffer3[count2],
- sizeof(buffer3) - (count1+count2),
- "%s%s%s\r\n",
- "--",BOUNDARY_STRING, "--");
- string status;
- cout << "Sending Post Headers" << endl<< buffer << endl << "End Post Headers" << endl;
- //Send the "POST" header to the HTTP server.
- if (send(sock, buffer, count, 0) == -1) {
- //status = perror("send");
- cout << "Stats Worker: received socket error %d on header send\n" << endl;
- return -1;
- }
- cout << "Hidden Data" << endl<< Buffer3 << endl << "End Post Headers" << endl;
- if (send(sock, Buffer3, hidden_data_len, 0) == -1) {
- //status = perror("send");
- cout << "Stats Worker: received socket error %d on header send\n" << endl;
- return -1;
- }
- cout << "Now Sending first part of the form data BUFFER1" << endl << buffer1 << endl<< "End First Part"<< endl;
- if (send(sock, buffer1, first_form_len, 0) == -1) {
- //status = CK_Get_last_error();
- cout << "Stats Worker: received socket error on header send\n" << endl;
- return -1;
- }
- cout << "Now Sending file " << Traveller_output_buffer << endl;
- //Now send the flat file
- if (send(sock, Traveller_output_buffer, data_len, 0) == -1) {
- //status = CK_Get_last_error();
- cout << "Stats Worker: received socket error %d on message send\n" << endl;
- return -1;
- }
- cout << "Sending ending boundary string " << endl << buffer3 << endl;
- if (send(sock, buffer3, count2, 0) == -1) {
- //status = perror("send");
- cout << "Stats Worker: received socket error %d on header send\n" << endl;
- return -1;
- }
- //Send the last part of the form data to the HTTP server.
- /*if (send(sock, buffer1+first_form_len, second_form_len, 0) == -1) {
- //status = CK_Get_last_error();
- cout << "Stats Worker: received socket error %d on header send\n" << endl;
- return -1;
- }*/
- //Receive server response
- n = recv(sock, buf, 2000, 0);
- //cout << "Server Response is " << endl << buf << endl;
- if(n < 0)
- {
- cout << "Upload Failed" << endl;
- return -1;
- }
- // Make sure this is a HTTP header
- if (!strstr(buf, "HTTP")) {
- cout << "Stats Worker: response doesn't contain HTTP\n";
- return -1;
- }
- if (n < 0) {
- cout << "Stats Worker: response status is " << n;
- return -1;
- }
- // while (n > 0) {
- //printf(buf);
- if(!strstr(buf, Successful_Upload))
- {
- cout << "Traveller Upload Failed. Server Responded " << buf;
- return -1;
- }
- else
- {
- cout << "Traveller Upload Successfull. \n Server Response is \n" << buf;
- //return 0;
- }
- //n = recv(sock, buf, 10480, 0);
- //}
- //remove("newtravellerdata.dat");
- //close(sock);
- }
Thanks,
Mohit