Search code examples
cbashshellwebserver

C-SERVER : HTTP response missing new line


C-SERVER:
execute external script : /script
response from script stored in "vvv" and "vvv" is sent to client.

fp = popen("/script", "r");
fgets(vvv, 500, fp);

write(client_fd, vvv, sizeof(vvv) - 1);
close(client_fd);

contents of /script

#!/bin/sh
echo -e 'HTTP/1.1 200 OK\r\n';

test with netcat:

echo TEST | nc <ip> <port>
HTTP/1.1 200 OK

problem: it fails to include a new line so it can work with web browser.

C-SERVER:

#include <arpa/inet.h>
#include <err.h>
#include <string.h>

char inn[100];

FILE *fp;
char vvv[100];

int main()
{
  int one = 1, client_fd;
  struct sockaddr_in svr_addr, cli_addr;
  socklen_t sin_len = sizeof(cli_addr);

  int sock = socket(AF_INET, SOCK_STREAM, 0);
  if (sock < 0)
    err(1, "can't open socket");

  setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(int));

  int port = 85;
  svr_addr.sin_family = AF_INET;
  svr_addr.sin_addr.s_addr = INADDR_ANY;
  svr_addr.sin_port = htons(port);

  if (bind(sock, (struct sockaddr *) &svr_addr, sizeof(svr_addr)) == -1) {
    close(sock);
    err(1, "Can't bind");
  }

  listen(sock, 5);
  while (1) {
    client_fd = accept(sock, (struct sockaddr *) &cli_addr, &sin_len);
    size_t bytesRead = read(client_fd,inn,sizeof(inn) - 1);

    fp = popen("/script", "r");
    fgets(vvv, 500, fp);
    printf(vvv);


    write(client_fd, vvv, sizeof(vvv) - 1);
    close(client_fd);
  }
}

Solution

  • Be aware that the HTTP header and content are separated by an empty line. This is also the case, if you don't provide any content at all.

    Also echo will already append a line break after the line. Use printf instead:

    #!/bin/sh
    printf 'HTTP/1.1 200 OK\r\n';
    printf '\r\n';
    printf 'Content'; # provide some content
    

    But this requires now that you need to read multiple lines from fp. Add an additional loop to read every line from fp:

    ...
    
    while (1) {
      client_fd = accept(sock, (struct sockaddr *) &cli_addr, &sin_len);
      size_t bytesRead = read(client_fd,inn,sizeof(inn) - 1);
    
      fp = popen("/script", "r");
    
      while (!feof(fp)) {
        // be careful here to use `sizeof` instead of the harcoded `500`
        fgets(vvv, sizeof(vvv), fp);
        // only write the number of bytes read
        write(client_fd, vvv, strlen(vvv));
        printf(vvv);
      }
    
      close(client_fd);
    }
    
    ...
    

    Also consider to use fread instead of fgets to prevent truncation of long lines.