5 #include <sys/socket.h>
12 void write_response(const void *object
, const char* buf
, size_t n
)
14 int sockfd
= *(int *)object
;
15 write(sockfd
, buf
, n
);
16 // TODO: error checking; repeat until all written.
19 /* Decode percent-escapes in place */
20 static void urldecode(char *p
) {
28 if (sscanf(p
, "%2hhx", w
) == 1) {
41 #define MAX_REQUEST_SZ 4096
42 static void handle_connection(int s
, respond_cb respond
, void *respond_object
)
44 char buf
[MAX_REQUEST_SZ
];
47 int r2
= read(s
, buf
+ r
, MAX_REQUEST_SZ
- r
);
55 if (sscanf(buf
, "%u:", &sz
) == 1) {
57 snprintf(buf2
, 16, "%u:,", sz
);
58 const int full_sz
= sz
+ strlen(buf2
);
60 if (full_sz
> MAX_REQUEST_SZ
) {
61 fprintf(stderr
, "Oversized request %u", sz
);
71 Request_Info requestInfo
= { };
73 if (buf
[r
-1] == ',' && buf
[r
-2] == ':') {
75 } else if (buf
[r
-1] != ',' || buf
[r
-2] != 0) {
76 fprintf(stderr
, "Bad request.");
81 while (*p
!= ':') p
++;
89 fprintf(stderr
, "Bad request.");
97 if (strcmp(key
, "QUERY_STRING") == 0) {
99 requestInfo
.query_string_decoded
= val
;
101 else if (strcmp(key
, "SCRIPT_PATH") == 0) requestInfo
.script_path
= val
;
102 else if (strcmp(key
, "PATH_INFO") == 0) requestInfo
.path_info
= val
;
103 else if (strcmp(key
, "SERVER_NAME") == 0) requestInfo
.server_name
= val
;
104 else if (strcmp(key
, "SERVER_PORT") == 0) requestInfo
.server_port
= val
;
105 else if (strcmp(key
, "REMOTE_ADDR") == 0) requestInfo
.remote_addr
= val
;
106 else if (strcmp(key
, "TLS_CLIENT_HASH") == 0) requestInfo
.tls_client_hash
= val
;
107 else if (strcmp(key
, "TLS_CLIENT_ISSUER") == 0) requestInfo
.tls_client_issuer
= val
;
108 else if (strcmp(key
, "TLS_CLIENT_ISSUER_CN") == 0) requestInfo
.tls_client_issuer_cn
= val
;
109 else if (strcmp(key
, "TLS_CLIENT_SUBJECT") == 0) requestInfo
.tls_client_subject
= val
;
110 else if (strcmp(key
, "TLS_CLIENT_SUBJECT_CN") == 0) requestInfo
.tls_client_subject_cn
= val
;
114 respond(respond_object
, &requestInfo
, write_response
, &s
);
117 void runSCGI(const char *socket_path
, respond_cb respond
, void *respond_object
)
119 // Unix socket gubbins based on
120 // https://beej.us/guide/bgipc/html/multi/unixsock.html
122 const int s
= socket(AF_UNIX
, SOCK_STREAM
, 0);
128 struct sockaddr_un local
;
129 local
.sun_family
= AF_UNIX
;
130 strcpy(local
.sun_path
, socket_path
);
131 unlink(local
.sun_path
);
132 if (bind(s
, (struct sockaddr
*)&local
,
133 strlen(local
.sun_path
) + sizeof(local
.sun_family
)) == -1) {
138 if (listen(s
, 20) == -1) {
144 const int s2
= accept(s
, NULL
, NULL
);
150 handle_connection(s2
, respond
, respond_object
);