Skip to content

Instantly share code, notes, and snippets.

@kig
Last active May 31, 2020 12:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kig/2ed6b51ecff5605a72bf4b502c793a48 to your computer and use it in GitHub Desktop.
Save kig/2ed6b51ecff5605a72bf4b502c793a48 to your computer and use it in GitHub Desktop.
A GLSL web server? Maybe?
#define CHR_NULL 0
#define CHR_SOH 1
#define CHR_STX 2
#define CHR_ETX 3
#define CHR_EOT 4
#define CHR_ENQ 5
#define CHR_ACK 6
#define CHR_BELL 7
#define CHR_BACKSPACE 8
#define CHR_TAB 9
#define CHR_LF 10
#define CHR_VT 11
#define CHR_FF 12
#define CHR_CR 13
#define CHR_SO 14
#define CHR_SI 15
#define CHR_DLE 16
#define CHR_DC1 17
#define CHR_DC2 18
#define CHR_DC3 19
#define CHR_DC4 20
#define CHR_NAK 21
#define CHR_SYN 22
#define CHR_ETB 23
#define CHR_CAN 24
#define CHR_EM 25
#define CHR_SUB 26
#define CHR_ESC 27
#define CHR_FS 28
#define CHR_GS 29
#define CHR_RS 30
#define CHR_US 31
#define CHR_SPACE 32
#define CHR_EXCLAMATION_MARK 33
#define CHR_DOUBLE_QUOTE 34
#define CHR_HASH 35
#define CHR_DOLLAR 36
#define CHR_PERCENT 37
#define CHR_AMPERSAND 38
#define CHR_SINGLE_QUOTE 39
#define CHR_OPEN_PAREN 40
#define CHR_CLOSE_PAREN 41
#define CHR_TIMES 42
#define CHR_PLUS 43
#define CHR_COMMA 44
#define CHR_DASH 45
#define CHR_DOT 46
#define CHR_SLASH 47
#define CHR_0 48
#define CHR_1 49
#define CHR_2 50
#define CHR_3 51
#define CHR_4 52
#define CHR_5 53
#define CHR_6 54
#define CHR_7 55
#define CHR_8 56
#define CHR_9 57
#define CHR_COLON 58
#define CHR_SEMICOLON 59
#define CHR_OPEN_ANGLE_BRACKET 60
#define CHR_EQUAL 61
#define CHR_CLOSE_ANGLE_BRACKET 62
#define CHR_QUESTION_MARK 63
#define CHR_AT 64
#define CHR_A 65
#define CHR_B 66
#define CHR_C 67
#define CHR_D 68
#define CHR_E 69
#define CHR_F 70
#define CHR_G 71
#define CHR_H 72
#define CHR_I 73
#define CHR_J 74
#define CHR_K 75
#define CHR_L 76
#define CHR_M 77
#define CHR_N 78
#define CHR_O 79
#define CHR_P 80
#define CHR_Q 81
#define CHR_R 82
#define CHR_S 83
#define CHR_T 84
#define CHR_U 85
#define CHR_V 86
#define CHR_W 87
#define CHR_X 88
#define CHR_Y 89
#define CHR_Z 90
#define CHR_OPEN_SQUARE_BRACKET 91
#define CHR_BACKSLASH 92
#define CHR_CLOSE_SQUARE_BRACKET 93
#define CHR_CARET 94
#define CHR_UNDERSCORE 95
#define CHR_BACKTICK 96
#define CHR_a 97
#define CHR_b 98
#define CHR_c 99
#define CHR_d 100
#define CHR_e 101
#define CHR_f 102
#define CHR_g 103
#define CHR_h 104
#define CHR_i 105
#define CHR_j 106
#define CHR_k 107
#define CHR_l 108
#define CHR_m 109
#define CHR_n 110
#define CHR_o 111
#define CHR_p 112
#define CHR_q 113
#define CHR_r 114
#define CHR_s 115
#define CHR_t 116
#define CHR_u 117
#define CHR_v 118
#define CHR_w 119
#define CHR_x 120
#define CHR_y 121
#define CHR_z 122
#define CHR_OPEN_CURLY_BRACKET 123
#define CHR_PIPE 124
#define CHR_CLOSE_CURLY_BRACKET 125
#define CHR_TILDE 126
#define CHR_DEL 127
// Compile with
// cpp httpd.glsl - | node preprocess.js > out.comp && glslangValidator -V out.comp -o httpd.spv
#define version #version
version 450
#include "chr.glsl"
#define strCopy(SRC, DST, i, start, end) uint _s = start; uint _e = end; while (_s < _e) (DST)[i++] = (SRC)[_s++];
#define strCopyAll(SRC, DST, i) uint _str[] = SRC; strCopy(_str, DST, i, 0, _str.length())
#define A_OK if (i > 1024) error(index); return
layout (local_size_x = 1, local_size_y = 1, local_size_z = 1 ) in;
layout(std430, binding = 0) readonly buffer inputBuffer { uint inputBytes[]; };
layout(std430, binding = 1) buffer outputBuffer { uint outputBytes[]; };
layout(std430, binding = 2) buffer heapBuffer { uint heap[]; };
layout(std430, binding = 3) buffer requestBuffer { uint request[]; };
layout(std430, binding = 4) buffer responseBuffer { uint response[]; };
const uint METHOD_UNKNOWN = 0;
const uint METHOD_GET = 1;
const uint METHOD_POST = 2;
const uint METHOD_OPTION = 3;
const uint PROTOCOL_UNKNOWN = 0;
const uint PROTOCOL_HTTP10 = 1;
const uint PROTOCOL_HTTP11 = 2;
const uint MIME_TEXT_PLAIN = 0;
const uint MIME_TEXT_HTML = 1;
struct header {
uvec2 name;
uvec2 value;
};
void readRequestUntilChar(inout uint i, uint index, uint endChar, out uvec2 str) {
str.x = index + i;
while (i < 1024 && request[index+i] != endChar) {
i++;
}
str.y = index + i;
i++;
}
void readMethod(inout uint i, uint index, out uint method) {
uint j = index + i;
uint c = request[j];
if (
request[j] == CHR_G &&
request[j+1] == CHR_E &&
request[j+2] == CHR_T &&
request[j+3] == CHR_SPACE
) {
method = METHOD_GET;
i += 4;
return;
} else if (
request[j] == CHR_P &&
request[j+1] == CHR_O &&
request[j+2] == CHR_S &&
request[j+3] == CHR_T &&
request[j+4] == CHR_SPACE
) {
method = METHOD_POST;
i += 5;
return;
} else if (request[j] == CHR_O && request[j+6] == CHR_SPACE) {
method = METHOD_OPTION;
i += 7;
return;
}
method = METHOD_UNKNOWN;
i = 1024;
}
void readPath(inout uint i, uint index, out uvec2 path) {
readRequestUntilChar(i, index, CHR_SPACE, path);
}
void readProtocol(inout uint i, uint index, out uint protocol) {
uvec2 protocolString;
readRequestUntilChar(i, index, CHR_CR, protocolString);
if (i < 1024 && request[index+i] == CHR_LF) {
i++;
if (request[protocolString.y-1] == CHR_1) {
protocol = PROTOCOL_HTTP11;
} else {
protocol = PROTOCOL_HTTP10;
}
} else {
protocol = PROTOCOL_UNKNOWN;
i = 1024;
}
}
bool readHeader(inout uint i, uint index, out header hdr) {
if (request[index+i] == CHR_CR) {
i += 2;
return true;
}
readRequestUntilChar(i, index, CHR_COLON, hdr.name);
while (i < 1024 && request[index+i] == CHR_SPACE) i++;
readRequestUntilChar(i, index, CHR_CR, hdr.value);
i += 2;
return false;
}
void writeStatus(inout uint i, uint index, uint statusCode) {
uint j = i + index;
strCopyAll("HTTP/1.1 ", response, j);
if (statusCode == 200) {
strCopyAll("200 OK", response, j);
} else {
strCopyAll("500 Error", response, j);
}
response[j++] = CHR_CR;
response[j++] = CHR_LF;
i = j - index;
}
void writeContentType(inout uint i, uint index, uint contentType) {
uint j = i + index;
uint contentTypeString[] = "Content-Type: ";
strCopyAll(contentTypeString, response, j);
if (contentType == MIME_TEXT_PLAIN) {
strCopyAll("text/plain", response, j);
} else {
strCopyAll("text/html", response, j);
}
response[j++] = CHR_CR;
response[j++] = CHR_LF;
i = j - index;
}
void writeEndHeaders(inout uint i, uint index) {
uint j = i + index;
response[j++] = CHR_CR;
response[j++] = CHR_LF;
i = j - index;
}
void writeBody(inout uint i, uint index, uvec2 path) {
uint j = i + index;
strCopyAll("Hello, World!", response, j);
i = j - index;
}
void error(uint index) {
uint i = index;
writeStatus(i, index, 500);
writeContentType(i, index, MIME_TEXT_PLAIN);
writeEndHeaders(i, index);
response[i++] = 0;
}
void unpackRequest(uint index) {
for (uint j = 0; j < 256; j++) {
uint v = inputBytes[index + j];
uint off = index + j * 4;
request[off + 0] = v & 0xFF;
request[off + 1] = (v >> 8) & 0xFF;
request[off + 2] = (v >> 16) & 0xFF;
request[off + 3] = v >> 24;
}
}
void packResponse(uint index) {
for (uint j = 0; j < 256; j++) {
uint off = index + j * 4;
outputBytes[index + j] = (
((response[off + 3] & 0xFF) << 24) |
((response[off + 2] & 0xFF) << 16) |
((response[off + 1] & 0xFF) << 8) |
(response[off + 0] & 0xFF)
);
}
}
void handleRequest(uint index) {
uint i = 0;
uint method;
uvec2 path;
uint protocol;
header headers[32];
uint headerCount = 0;
readMethod(i, index, method); A_OK;
readPath(i, index, path); A_OK;
readProtocol(i, index, protocol); A_OK;
for (uint j = 0; j < 32; j++) {
bool done = readHeader(i, index, headers[j]); A_OK;
if (done) break;
headerCount++;
}
i = 0;
writeStatus(i, index, 200); A_OK;
writeContentType(i, index, MIME_TEXT_PLAIN); A_OK;
writeEndHeaders(i, index); A_OK;
writeBody(i, index, path); A_OK;
response[i++] = 0;
}
void main() {
uint index = 1024 * (gl_GlobalInvocationID.x + gl_GlobalInvocationID.y * (gl_NumWorkGroups.x * gl_WorkGroupSize.x));
unpackRequest(index);
handleRequest(index);
packResponse(index);
}
// Turn string literals into uint arrays.
// Quick hack, doesn't deal with comments or tokenize \\\" correctly.
//
const fs = require('fs');
const source = fs.readFileSync(0);
const segments = source.toString().replace(/^# .*/mg, '').split(/(")/g);
let inString = false;
let lastSegment = '';
let stringSegments = [];
const output = [];
for (segment of segments) {
if (segment === '"' && lastSegment[lastSegment.length-1] !== '\\') {
inString = !inString;
if (!inString) {
const str = stringSegments.join('');
output.push(`{${Buffer.from(str).join(",")}}`);
}
stringSegments = [];
} else if (inString) {
stringSegments.push(segment);
} else {
output.push(segment);
}
lastSegment = segment;
}
console.log(output.join(''));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment