Search code examples
javacnetwork-programmingclient-serverserversocket

Http Post string from C client to Java server gives error 400 Bad Request


I have a C client and a Java server (Tomcat via eclipse).
1- The C client is meant to perform an HTTP Post of a string to the Java Server [Gives error].
2- The server has a localhost HTML form-page that is meant to save any string it receives which is posted and writes it to file [Works fine; Tested]

The problem I am having is that I am unable to get the server to successfully receive and save the string post from the client. The server responds with "error 400 bad request" instead.

However, I am able to get the server to save any string that is manually entered via the html form page.

I just need to get the client instead of me, to post to the html form page (unless there is a better way for the client to post to the server without the need of a form page).

I am no expert in network and socket programming. Any help is greatly appreciated.

Here is the Java Server Code:

// Import required java libraries
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.IOException;

// Extend HttpServlet class
public class HelloForm extends HttpServlet {

  private OutputStream ostream;
// Method to handle GET method request.
  public void doGet(HttpServletRequest request,
                    HttpServletResponse response)
            throws ServletException, IOException
  {
      // Set response content type
      response.setContentType("text/html");

      PrintWriter out = response.getWriter();
      String title = "Using GET Method to Read Form Data";
      String docType =
      "<!doctype html public \"-//w3c//dtd html 4.0 " +
      "transitional//en\">\n";
      out.println(docType +
                "<html>\n" +
                "<head><title>" + title + "</title></head>\n" +
                "<body bgcolor=\"#f0f0f0\">\n" +
                "<h1 align=\"center\">" + title + "</h1>\n" +
                "<ul>\n" +
                "  <li><b>First Parameter</b>: " //Displayed on result page NOT html page
                + request.getParameter("first_name") + "\n" +
                "  <li><b>Last Parameter</b>: " //Displayed on result page NOT html page
                + request.getParameter("last_name") + "\n" +
                "</ul>\n" +
                "</body></html>");
      //printing result to console:
      System.out.println(request.getParameter("first_name"));
      System.out.printf("Parameter Entered: %s\n", request.getParameter("first_name"));

    ////printing results to file:
         {

try(PrintWriter serveroutput = new PrintWriter(new BufferedWriter(new FileWriter("/home/salimramjean/Desktop/ServerOutput.txt",true)))) {
    serveroutput.println(request.getParameter("first_name"));

            } 

        }       
  }
  // Method to handle POST method request.
  public void doPost(HttpServletRequest request,
                     HttpServletResponse response)
      throws ServletException, IOException {
     doGet(request, response);
  }
}

HTML form page of server:

    <html>
<body>
    <form action="HelloForm" method="POST">
        Parameter: <input type="text" name="first_name">
                    <br />
                    <input type="submit" value="Submit" />
    </form>
</body>
</html>
<?

Here is the C Client code:

    #include <stdio.h> /* printf, sprintf */
#include <stdlib.h> /* read, write, close */
#include <string.h> /* memcpy, memset */
#include <sys/socket.h> /* socket, connect */
#include <netinet/in.h> /* struct sockaddr_in, struct sockaddr */
#include <netdb.h> /* struct hostent, gethostbyname */
#include <unistd.h>

void error(const char *msg) { perror(msg); exit(0); }

int main(int argc,char *argv[])
{
    /* first what are we going to send and where are we going to send it? */
    int portno =        8080; 
    char *host =        "192.168.1.65"; /* localhost: 127.0.0.1 or 192.168.1.65 */
    char *message_fmt = "POST /Parameter=%s&command=%s HTTP/1.1\n\n";

    struct hostent *server;
    struct sockaddr_in serv_addr;
    int sockfd, bytes, sent, received, total;
    char message[1024],response[4096];

    if (argc < 3) { puts("Parameters: <apikey> <command>"); exit(0); }



    /* fill in the parameters */
    sprintf(message,message_fmt,argv[1],argv[2]); 
    printf("Request:\n%s\n",message);

    /* create the socket */
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) error("ERROR opening socket");

    /* lookup the ip address */
    server = gethostbyname(host);
    printf("ip address: %s\n\n", host);
    if (server == NULL) error("ERROR, no such host");

    /* fill in the structure */
    memset(&serv_addr,0,sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(portno);
    memcpy(&serv_addr.sin_addr.s_addr,server->h_addr,server->h_length);

    /* connect the socket */
    if (connect(sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0)
        error("ERROR connecting");
  /* send the request */
printf("Sending request\n\n");
total = strlen(message);
    sent = 0;
    do {
       //bytes = write(sockfd,a+sent,total-sent);
      bytes = write(sockfd,message+sent,total-sent);
        if (bytes < 0)
            error("ERROR writing message to socket");
        if (bytes == 0)
            break;
        sent+=bytes;
    } while (sent < total); //while (sent < 0);
    printf("Post request sent \n");

    //receive the response
    printf("Receiving response \n");
    memset(response,0,sizeof(response));
    total = sizeof(response)-1;
    received = 0;
    do {
        bytes = read(sockfd,response-received,total-received);
        if (bytes < 0)
            error("ERROR reading response from socket");
        if (bytes == 0)
            break;
        received+=bytes;
    } while(received < total); //while (received < 0);
    printf("Response received\n");

    if (received == total)
        error("ERROR storing complete response from socket");

    /* close the socket */
    close(sockfd);

    /* process response */
    printf("\nServer Response:\n%s\n\n",response);

    return 0;
}

Here is the web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0">
  <display-name>FormServ</display-name>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>default.html</welcome-file>
    <welcome-file>default.htm</welcome-file>
    <welcome-file>default.jsp</welcome-file>
  </welcome-file-list>

  <servlet>
        <servlet-name>HelloForm</servlet-name>
        <servlet-class>HelloForm</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>HelloForm</servlet-name>
        <url-pattern>/HelloForm</url-pattern>
    </servlet-mapping>

</web-app>

Example of how I run and compile it:
$ ./client IamSendingThisString submit

Result displayed in Terminal:

Request:
POST /Parameter=IamSendingThisString&command=submit HTTP/1.1


ip address: 192.168.1.65

Sending request

Post request sent 
Receiving response 
Response received

Server Response:
HTTP/1.1 400 Bad Request
Server: Apache-Coyote/1.1
Transfer-Encoding: chunked
Date: Tue, 24 Feb 2015 09:22:15 GMT
Connection: close

0

Correct Changes made:

1- Edited POST header:
char *message_fmt = "POST /FormServ/HelloForm HTTP/1.1\r\nHost: %s:%d\r\nContent-Type: %s\r\nContent-Length: %d\r\n\r\nfirst_name=%s&last_name=%s\r\n"; 

2- Added content type:
char *contentType = "application/x-www-form-urlencoded";

3- Added Content length

Solution

  • Your problem in this line: "POST /Parameter=%s&command=%s HTTP/1.1\n\n"

    I don't know what exactly parameters should be send, but it contains at least 2 errors:

    1) Doesn't have symbol ? before prameters list. Should be /?Parameter=%s&command=%s if your servlet deployed in /, not some other page like /index.jsp

    2) Doesn't ends with \r\n (ends with \n\n instead)

    Also maybe you should send headers Content-length, Content-type and additional \r\n in the end or request.

    Try to find some working socket client example and copy code. For example http://examples.javacodegeeks.com/core-java/net/socket/send-http-post-request-with-socket/