Add bits to support HTTP in server
This commit is contained in:
221
lib/ipc/server.c
221
lib/ipc/server.c
@@ -36,6 +36,8 @@
|
|||||||
#include "hi_locl.h"
|
#include "hi_locl.h"
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
|
#define MAX_PACKET_SIZE (128 * 1024)
|
||||||
|
|
||||||
struct heim_sipc {
|
struct heim_sipc {
|
||||||
int (*release)(heim_sipc ctx);
|
int (*release)(heim_sipc ctx);
|
||||||
heim_ipc_callback callback;
|
heim_ipc_callback callback;
|
||||||
@@ -448,6 +450,12 @@ struct client {
|
|||||||
#define WAITING_READ 2
|
#define WAITING_READ 2
|
||||||
#define WAITING_WRITE 4
|
#define WAITING_WRITE 4
|
||||||
#define WAITING_CLOSE 8
|
#define WAITING_CLOSE 8
|
||||||
|
|
||||||
|
#define HTTP_REPLY 16
|
||||||
|
|
||||||
|
#define INHERIT_MASK 0xffff0000
|
||||||
|
#define INCLUDE_ERROR_CODE (1 << 16)
|
||||||
|
#define ALLOW_HTTP (1<<17)
|
||||||
unsigned calls;
|
unsigned calls;
|
||||||
size_t ptr, len;
|
size_t ptr, len;
|
||||||
uint8_t *inmsg;
|
uint8_t *inmsg;
|
||||||
@@ -576,7 +584,10 @@ socket_complete(heim_sipc_call ctx, int returnvalue, heim_idata *reply)
|
|||||||
if ((c->flags & WAITING_CLOSE) == 0) {
|
if ((c->flags & WAITING_CLOSE) == 0) {
|
||||||
uint8_t *ptr;
|
uint8_t *ptr;
|
||||||
uint32_t u32;
|
uint32_t u32;
|
||||||
size_t rlen = reply->length + sizeof(u32) + sizeof(u32);
|
size_t rlen = reply->length + sizeof(u32);
|
||||||
|
|
||||||
|
if (c->flags & INCLUDE_ERROR_CODE)
|
||||||
|
rlen += sizeof(u32);
|
||||||
|
|
||||||
c->outmsg = erealloc(c->outmsg, c->olen + rlen);
|
c->outmsg = erealloc(c->outmsg, c->olen + rlen);
|
||||||
|
|
||||||
@@ -587,9 +598,11 @@ socket_complete(heim_sipc_call ctx, int returnvalue, heim_idata *reply)
|
|||||||
ptr += sizeof(u32);
|
ptr += sizeof(u32);
|
||||||
|
|
||||||
/* return value */
|
/* return value */
|
||||||
u32 = htonl(returnvalue);
|
if (c->flags & INCLUDE_ERROR_CODE) {
|
||||||
memcpy(ptr, &u32, sizeof(u32));
|
u32 = htonl(returnvalue);
|
||||||
ptr += sizeof(u32);
|
memcpy(ptr, &u32, sizeof(u32));
|
||||||
|
ptr += sizeof(u32);
|
||||||
|
}
|
||||||
|
|
||||||
/* data */
|
/* data */
|
||||||
memcpy(ptr, reply->data, reply->length);
|
memcpy(ptr, reply->data, reply->length);
|
||||||
@@ -606,6 +619,119 @@ socket_complete(heim_sipc_call ctx, int returnvalue, heim_idata *reply)
|
|||||||
maybe_close(c);
|
maybe_close(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* remove HTTP %-quoting from buf */
|
||||||
|
static int
|
||||||
|
de_http(char *buf)
|
||||||
|
{
|
||||||
|
unsigned char *p, *q;
|
||||||
|
for(p = q = (unsigned char *)buf; *p; p++, q++) {
|
||||||
|
if(*p == '%' && isxdigit(p[1]) && isxdigit(p[2])) {
|
||||||
|
unsigned int x;
|
||||||
|
if(sscanf((char *)p + 1, "%2x", &x) != 1)
|
||||||
|
return -1;
|
||||||
|
*q = x;
|
||||||
|
p += 2;
|
||||||
|
} else
|
||||||
|
*q = *p;
|
||||||
|
}
|
||||||
|
*q = '\0';
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct socket_call *
|
||||||
|
handle_http_tcp(struct client *c)
|
||||||
|
{
|
||||||
|
struct socket_call *cs;
|
||||||
|
char *s, *p, *t;
|
||||||
|
void *data;
|
||||||
|
char *proto;
|
||||||
|
int len;
|
||||||
|
|
||||||
|
s = (char *)d->inmsg;
|
||||||
|
|
||||||
|
p = strstr(s, "\r\n");
|
||||||
|
if (p == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
*p = 0;
|
||||||
|
|
||||||
|
p = NULL;
|
||||||
|
t = strtok_r(s, " \t", &p);
|
||||||
|
if (t == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
t = strtok_r(NULL, " \t", &p);
|
||||||
|
if (t == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
data = malloc(strlen(t));
|
||||||
|
if (data == NULL) {
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if(*t == '/')
|
||||||
|
t++;
|
||||||
|
if(de_http(t) != 0) {
|
||||||
|
free(data);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
proto = strtok_r(NULL, " \t", &p);
|
||||||
|
if (proto == NULL) {
|
||||||
|
free(data);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
len = base64_decode(t, data);
|
||||||
|
if(len <= 0){
|
||||||
|
const char *msg =
|
||||||
|
" 404 Not found\r\n"
|
||||||
|
"Server: Heimdal/" VERSION "\r\n"
|
||||||
|
"Cache-Control: no-cache\r\n"
|
||||||
|
"Pragma: no-cache\r\n"
|
||||||
|
"Content-type: text/html\r\n"
|
||||||
|
"Content-transfer-encoding: 8bit\r\n\r\n"
|
||||||
|
"<TITLE>404 Not found</TITLE>\r\n"
|
||||||
|
"<H1>404 Not found</H1>\r\n"
|
||||||
|
"That page doesn't exist, maybe you are looking for "
|
||||||
|
"<A HREF=\"http://www.h5l.org/\">Heimdal</A>?\r\n";
|
||||||
|
free(data);
|
||||||
|
if (rk_IS_SOCKET_ERROR(send(d->s, proto, strlen(proto), 0))) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (rk_IS_SOCKET_ERROR(send(d->s, msg, strlen(msg), 0))) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
cs = emalloc(sizeof(*cs));
|
||||||
|
cs->c = c;
|
||||||
|
cs->in.data = data;
|
||||||
|
cs->in.length = len;
|
||||||
|
c->ptr = 0;
|
||||||
|
|
||||||
|
{
|
||||||
|
const char *msg =
|
||||||
|
" 200 OK\r\n"
|
||||||
|
"Server: Heimdal/" VERSION "\r\n"
|
||||||
|
"Cache-Control: no-cache\r\n"
|
||||||
|
"Pragma: no-cache\r\n"
|
||||||
|
"Content-type: application/octet-stream\r\n"
|
||||||
|
"Content-transfer-encoding: binary\r\n\r\n";
|
||||||
|
if (rk_IS_SOCKET_ERROR(send(d->s, proto, strlen(proto), 0))) {
|
||||||
|
free(data);
|
||||||
|
free(cs);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (rk_IS_SOCKET_ERROR(send(d->s, msg, strlen(msg), 0))) {
|
||||||
|
free(data);
|
||||||
|
free(cs);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return cs;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
handle_read(struct client *c)
|
handle_read(struct client *c)
|
||||||
{
|
{
|
||||||
@@ -614,7 +740,7 @@ handle_read(struct client *c)
|
|||||||
|
|
||||||
if (c->flags & LISTEN_SOCKET) {
|
if (c->flags & LISTEN_SOCKET) {
|
||||||
add_new_socket(c->fd,
|
add_new_socket(c->fd,
|
||||||
WAITING_READ,
|
WAITING_READ | (c->flags & INHERIT_MASK),
|
||||||
c->callback,
|
c->callback,
|
||||||
c->userctx);
|
c->userctx);
|
||||||
return;
|
return;
|
||||||
@@ -639,22 +765,45 @@ handle_read(struct client *c)
|
|||||||
while (c->ptr >= sizeof(dlen)) {
|
while (c->ptr >= sizeof(dlen)) {
|
||||||
struct socket_call *cs;
|
struct socket_call *cs;
|
||||||
|
|
||||||
memcpy(&dlen, c->inmsg, sizeof(dlen));
|
if((c->flags & ALLOW_HTTP) && c->ptr >= 4 &&
|
||||||
dlen = ntohl(dlen);
|
strncmp((char *)c->inmsg, "GET ", 4) == 0 &&
|
||||||
|
strncmp((char *)c->inmsg + c->ptr - 4, "\r\n\r\n", 4) == 0) {
|
||||||
|
|
||||||
|
/* remove the trailing \r\n\r\n so the string is NUL terminated */
|
||||||
|
c->inmsg[c->ptr - 4] = '\0';
|
||||||
|
|
||||||
|
c->flags |= HTTP_REPLY;
|
||||||
|
|
||||||
|
cs = handle_http_tcp(c);
|
||||||
|
if (cs == NULL) {
|
||||||
|
c->flags |= WAITING_CLOSE;
|
||||||
|
c->flags &= ~WAITING_READ;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
memcpy(&dlen, c->inmsg, sizeof(dlen));
|
||||||
|
dlen = ntohl(dlen);
|
||||||
|
|
||||||
|
if (dlen > MAX_PACKET_SIZE) {
|
||||||
|
c->flags |= WAITING_CLOSE;
|
||||||
|
c->flags &= ~WAITING_READ;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (dlen < c->ptr - sizeof(dlen)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (dlen < c->ptr - sizeof(dlen))
|
cs = emalloc(sizeof(*cs));
|
||||||
break;
|
cs->c = c;
|
||||||
|
cs->in.data = emalloc(dlen);
|
||||||
|
memcpy(cs->in.data, c->inmsg + sizeof(dlen), dlen);
|
||||||
|
cs->in.length = dlen;
|
||||||
|
|
||||||
cs = emalloc(sizeof(*cs));
|
c->ptr -= sizeof(dlen) + dlen;
|
||||||
cs->c = c;
|
memmove(c->inmsg,
|
||||||
cs->in.data = emalloc(dlen);
|
c->inmsg + sizeof(dlen) + dlen,
|
||||||
memcpy(cs->in.data, c->inmsg + sizeof(dlen), dlen);
|
c->ptr);
|
||||||
cs->in.length = dlen;
|
}
|
||||||
|
|
||||||
c->ptr -= sizeof(dlen) + dlen;
|
|
||||||
memmove(c->inmsg,
|
|
||||||
c->inmsg + sizeof(dlen) + dlen,
|
|
||||||
c->ptr);
|
|
||||||
|
|
||||||
c->calls++;
|
c->calls++;
|
||||||
c->callback(c->userctx, &cs->in,
|
c->callback(c->userctx, &cs->in,
|
||||||
@@ -753,15 +902,36 @@ socket_release(heim_sipc ctx)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define HEIM_SIPC_TYPE_IPC 1
|
||||||
|
#define HEIM_SIPC_TYPE_UINT32 2
|
||||||
|
#define HEIM_SIPC_TYPE_HTTP 4
|
||||||
|
|
||||||
int
|
int
|
||||||
heim_sipc_launchd_stream_fd_init(int fd,
|
heim_sipc_stream_listener(int fd,
|
||||||
heim_ipc_callback callback,
|
int type,
|
||||||
void *user, heim_sipc *ctx)
|
heim_ipc_callback callback,
|
||||||
|
void *user, heim_sipc *ctx)
|
||||||
{
|
{
|
||||||
heim_sipc ct = calloc(1, sizeof(*ct));
|
heim_sipc ct = calloc(1, sizeof(*ct));
|
||||||
struct client *c;
|
struct client *c;
|
||||||
|
|
||||||
c = add_new_socket(fd, LISTEN_SOCKET|WAITING_READ, callback, user);
|
if ((type & HEIM_SIPC_TYPE_IPC) && (type & (HEIM_SIPC_TYPE_UINT32|HEIM_SIPC_TYPE_HTTP)))
|
||||||
|
return EINVAL;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case HEIM_SIPC_TYPE_IPC:
|
||||||
|
c = add_new_socket(fd, LISTEN_SOCKET|WAITING_READ|INCLUDE_ERROR_CODE, callback, user);
|
||||||
|
break;
|
||||||
|
case HEIM_SIPC_TYPE_UINT32:
|
||||||
|
c = add_new_socket(fd, LISTEN_SOCKET|WAITING_READ, callback, user);
|
||||||
|
break;
|
||||||
|
case HEIM_SIPC_TYPE_UINT32|HEIM_SIPC_TYPE_HTTP:
|
||||||
|
c = add_new_socket(fd, LISTEN_SOCKET|WAITING_READ|ALLOW_HTTP, callback, user);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
free(ct);
|
||||||
|
return EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
ct->mech = c;
|
ct->mech = c;
|
||||||
ct->release = socket_release;
|
ct->release = socket_release;
|
||||||
@@ -769,7 +939,6 @@ heim_sipc_launchd_stream_fd_init(int fd,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
heim_sipc_service_unix(const char *service,
|
heim_sipc_service_unix(const char *service,
|
||||||
heim_ipc_callback callback,
|
heim_ipc_callback callback,
|
||||||
@@ -808,11 +977,9 @@ heim_sipc_service_unix(const char *service,
|
|||||||
|
|
||||||
chmod(un.sun_path, 0666);
|
chmod(un.sun_path, 0666);
|
||||||
|
|
||||||
return heim_sipc_launchd_stream_fd_init(fd, callback, user, ctx);
|
return heim_sipc_stream_listener(fd, HEIM_SIPC_TYPE_IPC, callback, user, ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the idle timeout value
|
* Set the idle timeout value
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user