// File: nilnilnil[P]autocomplete/deps/mongoose/mongoose.c
// Function: handle_cgi_request
static void handle_cgi_request(struct mg_connection *conn, const char *prog) {
  int headers_len, data_len, i, fd_stdin[2], fd_stdout[2];
  const char *status;
  char buf[BUFSIZ], *pbuf, dir[PATH_MAX], *p;
  struct mg_request_info ri;
  struct cgi_env_block blk;
  FILE *in, *out;
  pid_t pid;

  prepare_cgi_environment(conn, prog, &blk);

  // CGI must be executed in its own directory. 'dir' must point to the
  // directory containing executable program, 'p' must point to the
  // executable program name relative to 'dir'.
  (void) mg_snprintf(conn, dir, sizeof(dir), "%s", prog);
  if ((p = strrchr(dir, DIRSEP)) != NULL) {
    *p++ = '\0';
  } else {
    dir[0] = '.', dir[1] = '\0';
    p = (char *) prog;
  }

  pid = (pid_t) -1;
  fd_stdin[0] = fd_stdin[1] = fd_stdout[0] = fd_stdout[1] = -1;
  in = out = NULL;

  if (pipe(fd_stdin) != 0 || pipe(fd_stdout) != 0) {
    send_http_error(conn, 500, http_500_error,
        "Cannot create CGI pipe: %s", strerror(ERRNO));
    goto done;
  } else if ((pid = spawn_process(conn, p, blk.buf, blk.vars,
          fd_stdin[0], fd_stdout[1], dir)) == (pid_t) -1) {
    goto done;
  } else if ((in = fdopen(fd_stdin[1], "wb")) == NULL ||
      (out = fdopen(fd_stdout[0], "rb")) == NULL) {
    send_http_error(conn, 500, http_500_error,
        "fopen: %s", strerror(ERRNO));
    goto done;
  }

  setbuf(in, NULL);
  setbuf(out, NULL);

  // spawn_process() must close those!
  // If we don't mark them as closed, close() attempt before
  // return from this function throws an exception on Windows.
  // Windows does not like when closed descriptor is closed again.
  fd_stdin[0] = fd_stdout[1] = -1;

  // Send POST data to the CGI process if needed
  if (!strcmp(conn->request_info.request_method, "POST") &&
      !forward_body_data(conn, in, INVALID_SOCKET, NULL)) {
    goto done;
  }

  // Now read CGI reply into a buffer. We need to set correct
  // status code, thus we need to see all HTTP headers first.
  // Do not send anything back to client, until we buffer in all
  // HTTP headers.
  data_len = 0;
  headers_len = read_request(out, INVALID_SOCKET, NULL,
      buf, sizeof(buf), &data_len);
  if (headers_len <= 0) {
    send_http_error(conn, 500, http_500_error,
                    "CGI program sent malformed HTTP headers: [%.*s]",
                    data_len, buf);
    goto done;
  }
  pbuf = buf;
  buf[headers_len - 1] = '\0';
  parse_http_headers(&pbuf, &ri);

  // Make up and send the status line
  status = get_header(&ri, "Status");
  conn->request_info.status_code = status == NULL ? 200 : atoi(status);
  (void) mg_printf(conn, "HTTP/1.1 %d OK\r\n", conn->request_info.status_code);

  // Send headers
  for (i = 0; i < ri.num_headers; i++) {
    mg_printf(conn, "%s: %s\r\n",
              ri.http_headers[i].name, ri.http_headers[i].value);
  }
  (void) mg_write(conn, "\r\n", 2);

  // Send chunk of data that may be read after the headers
  conn->num_bytes_sent += mg_write(conn, buf + headers_len,
                                   (size_t)(data_len - headers_len));

  // Read the rest of CGI output and send to the client
  send_file_data(conn, out, INT64_MAX);

done:
  if (pid != (pid_t) -1) {
    kill(pid, SIGKILL);
#if !defined(_WIN32)
    do {} while (waitpid(-1, &i, WNOHANG) > 0);
#endif
  }
  if (fd_stdin[0] != -1) {
    (void) close(fd_stdin[0]);
  }
  if (fd_stdout[1] != -1) {
    (void) close(fd_stdout[1]);
  }

  if (in != NULL) {
    (void) fclose(in);
  } else if (fd_stdin[1] != -1) {
    (void) close(fd_stdin[1]);
  }

  if (out != NULL) {
    (void) fclose(out);
  } else if (fd_stdout[0] != -1) {
    (void) close(fd_stdout[0]);
  }
}

// Assembly:
subq $0x4708, %rsp           # imm = 0x4708
movq %rdi, 0x4700(%rsp)
movq %rsi, 0x46f8(%rsp)
movq 0x4700(%rsp), %rdi
movq 0x46f8(%rsp), %rsi
leaq 0x50(%rsp), %rdx
callq 0x1ff10
movq 0x4700(%rsp), %rdi
leaq 0x16c0(%rsp), %rsi
movq 0x46f8(%rsp), %r8
movl $0x1000, %edx           # imm = 0x1000
leaq 0x52d3(%rip), %rcx      # 0x23778
movb $0x0, %al
callq 0x1cc90
leaq 0x16c0(%rsp), %rdi
movl $0x2f, %esi
callq 0x5630
movq %rax, 0x16b8(%rsp)
cmpq $0x0, %rax
je 0x1e4e8
movq 0x16b8(%rsp), %rax
movq %rax, %rcx
addq $0x1, %rcx
movq %rcx, 0x16b8(%rsp)
movb $0x0, (%rax)
jmp 0x1e508
movb $0x2e, 0x16c0(%rsp)
movb $0x0, 0x16c1(%rsp)
movq 0x46f8(%rsp), %rax
movq %rax, 0x16b8(%rsp)
movl $0xffffffff, 0x3c(%rsp) # imm = 0xFFFFFFFF
movl $0xffffffff, 0x46e0(%rsp) # imm = 0xFFFFFFFF
movl $0xffffffff, 0x46dc(%rsp) # imm = 0xFFFFFFFF
movl $0xffffffff, 0x46e8(%rsp) # imm = 0xFFFFFFFF
movl $0xffffffff, 0x46e4(%rsp) # imm = 0xFFFFFFFF
movq $0x0, 0x40(%rsp)
movq $0x0, 0x48(%rsp)
leaq 0x46e4(%rsp), %rdi
callq 0x57d0
cmpl $0x0, %eax
jne 0x1e572
leaq 0x46dc(%rsp), %rdi
callq 0x57d0
cmpl $0x0, %eax
je 0x1e5bc
movq 0x4700(%rsp), %rax
movq %rax, 0x28(%rsp)
movq 0xd4da(%rip), %rax      # 0x2ba60
movq %rax, 0x30(%rsp)
callq 0x5060
movl (%rax), %edi
callq 0x5190
movq 0x28(%rsp), %rdi
movq 0x30(%rsp), %rdx
movq %rax, %r8
movl $0x1f4, %esi            # imm = 0x1F4
leaq 0x4f9f(%rip), %rcx      # 0x2354f
movb $0x0, %al
callq 0x1bc40
jmp 0x1e936
movq 0x4700(%rsp), %rdi
movq 0x16b8(%rsp), %rsi
leaq 0x50(%rsp), %rdx
addq $0x8, %rdx
leaq 0x50(%rsp), %rcx
addq $0x1010, %rcx           # imm = 0x1010
movl 0x46e4(%rsp), %r8d
movl 0x46e0(%rsp), %r9d
leaq 0x16c0(%rsp), %rax
movq %rax, (%rsp)
callq 0x20480
movl %eax, 0x3c(%rsp)
cmpl $-0x1, %eax
jne 0x1e610
jmp 0x1e936
movl 0x46e8(%rsp), %edi
leaq 0x4f4c(%rip), %rsi      # 0x2356a
callq 0x55d0
movq %rax, 0x48(%rsp)
cmpq $0x0, %rax
je 0x1e64c
movl 0x46dc(%rsp), %edi
leaq 0x4f31(%rip), %rsi      # 0x2356d
callq 0x55d0
movq %rax, 0x40(%rsp)
cmpq $0x0, %rax
jne 0x1e696
movq 0x4700(%rsp), %rax
movq %rax, 0x18(%rsp)
movq 0xd400(%rip), %rax      # 0x2ba60
movq %rax, 0x20(%rsp)
callq 0x5060
movl (%rax), %edi
callq 0x5190
movq 0x18(%rsp), %rdi
movq 0x20(%rsp), %rdx
movq %rax, %r8
movl $0x1f4, %esi            # imm = 0x1F4
leaq 0x4ee6(%rip), %rcx      # 0x23570
movb $0x0, %al
callq 0x1bc40
jmp 0x1e936
jmp 0x1e698
jmp 0x1e69a
movq 0x48(%rsp), %rdi
xorl %eax, %eax
movl %eax, %esi
callq 0x5840
movq 0x40(%rsp), %rdi
xorl %eax, %eax
movl %eax, %esi
callq 0x5840
movl $0xffffffff, 0x46e0(%rsp) # imm = 0xFFFFFFFF
movl $0xffffffff, 0x46e4(%rsp) # imm = 0xFFFFFFFF
movq 0x4700(%rsp), %rax
movq 0x10(%rax), %rdi
leaq 0x483c(%rip), %rsi      # 0x22f1b
callq 0x5810
cmpl $0x0, %eax
jne 0x1e70e
movq 0x4700(%rsp), %rdi
movq 0x48(%rsp), %rsi
movl $0xffffffff, %edx       # imm = 0xFFFFFFFF
xorl %eax, %eax
movl %eax, %ecx
callq 0x1d4c0
cmpl $0x0, %eax
jne 0x1e70e
jmp 0x1e936
movl $0x0, 0x46f0(%rsp)
movq 0x40(%rsp), %rdi
leaq 0x26d0(%rsp), %rcx
movl $0xffffffff, %esi       # imm = 0xFFFFFFFF
xorl %eax, %eax
movl %eax, %edx
movl $0x2000, %r8d           # imm = 0x2000
leaq 0x46f0(%rsp), %r9
callq 0x1bb80
movl %eax, 0x46f4(%rsp)
cmpl $0x0, 0x46f4(%rsp)
jg 0x1e78a
movq 0x4700(%rsp), %rdi
movq 0xd2fe(%rip), %rdx      # 0x2ba60
movl 0x46f0(%rsp), %r8d
leaq 0x26d0(%rsp), %r9
movl $0x1f4, %esi            # imm = 0x1F4
leaq 0x4dfc(%rip), %rcx      # 0x2357a
movb $0x0, %al
callq 0x1bc40
jmp 0x1e936
leaq 0x26d0(%rsp), %rax
movq %rax, 0x26c8(%rsp)
movl 0x46f4(%rsp), %eax
subl $0x1, %eax
cltq
movb $0x0, 0x26d0(%rsp,%rax)
leaq 0x26c8(%rsp), %rdi
leaq 0x1268(%rsp), %rsi
callq 0x1cea0
leaq 0x1268(%rsp), %rdi
leaq 0x4dd8(%rip), %rsi      # 0x235aa
callq 0x16ba0
movq %rax, 0x46d0(%rsp)
cmpq $0x0, 0x46d0(%rsp)
jne 0x1e7f5
movl $0xc8, %eax
movl %eax, 0x14(%rsp)
jmp 0x1e806
movq 0x46d0(%rsp), %rdi
callq 0x5950
movl %eax, 0x14(%rsp)
movl 0x14(%rsp), %ecx
movq 0x4700(%rsp), %rax
movl %ecx, 0x4c(%rax)
movq 0x4700(%rsp), %rdi
movq 0x4700(%rsp), %rax
movl 0x4c(%rax), %edx
leaq 0x4d82(%rip), %rsi      # 0x235b1
movb $0x0, %al
callq 0x17030
movl $0x0, 0x46ec(%rsp)
movl 0x46ec(%rsp), %eax
cmpl 0x12b4(%rsp), %eax
jge 0x1e8b7
movq 0x4700(%rsp), %rdi
leaq 0x1268(%rsp), %rax
addq $0x50, %rax
movslq 0x46ec(%rsp), %rcx
shlq $0x4, %rcx
addq %rcx, %rax
movq (%rax), %rdx
leaq 0x1268(%rsp), %rax
addq $0x50, %rax
movslq 0x46ec(%rsp), %rcx
shlq $0x4, %rcx
addq %rcx, %rax
movq 0x8(%rax), %rcx
leaq 0x46fa(%rip), %rsi      # 0x22f97
movb $0x0, %al
callq 0x17030
movl 0x46ec(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x46ec(%rsp)
jmp 0x1e841
movq 0x4700(%rsp), %rdi
leaq 0x4982(%rip), %rsi      # 0x23248
movl $0x2, %edx
callq 0x16ed0
movq 0x4700(%rsp), %rdi
leaq 0x26d0(%rsp), %rsi
movslq 0x46f4(%rsp), %rax
addq %rax, %rsi
movl 0x46f0(%rsp), %eax
subl 0x46f4(%rsp), %eax
movslq %eax, %rdx
callq 0x16ed0
movslq %eax, %rcx
movq 0x4700(%rsp), %rax
addq 0x4b0(%rax), %rcx
movq %rcx, 0x4b0(%rax)
movq 0x4700(%rsp), %rdi
movq 0x40(%rsp), %rsi
movabsq $0x7fffffffffffffff, %rdx # imm = 0x7FFFFFFFFFFFFFFF
callq 0x207c0
cmpl $-0x1, 0x3c(%rsp)
je 0x1e96b
movl 0x3c(%rsp), %edi
movl $0x9, %esi
callq 0x5830
jmp 0x1e94d
movl $0xffffffff, %edi       # imm = 0xFFFFFFFF
leaq 0x46ec(%rsp), %rsi
movl $0x1, %edx
callq 0x5410
cmpl $0x0, %eax
jg 0x1e94b
jmp 0x1e96b
cmpl $-0x1, 0x46e4(%rsp)
je 0x1e981
movl 0x46e4(%rsp), %edi
callq 0x5b70
cmpl $-0x1, 0x46e0(%rsp)
je 0x1e997
movl 0x46e0(%rsp), %edi
callq 0x5b70
cmpq $0x0, 0x48(%rsp)
je 0x1e9ab
movq 0x48(%rsp), %rdi
callq 0x5560
jmp 0x1e9c3
cmpl $-0x1, 0x46e8(%rsp)
je 0x1e9c1
movl 0x46e8(%rsp), %edi
callq 0x5b70
jmp 0x1e9c3
cmpq $0x0, 0x40(%rsp)
je 0x1e9d7
movq 0x40(%rsp), %rdi
callq 0x5560
jmp 0x1e9ef
cmpl $-0x1, 0x46dc(%rsp)
je 0x1e9ed
movl 0x46dc(%rsp), %edi
callq 0x5b70
jmp 0x1e9ef
addq $0x4708, %rsp           # imm = 0x4708
retq
nopw (%rax,%rax)