Hypersonic
view release on metacpan or search on metacpan
lib/Hypersonic/Stream.pm view on Meta::CPAN
$class->gen_xs_headers($builder);
$class->gen_xs_content_type($builder);
$class->gen_xs_write($builder);
$class->gen_xs_end($builder);
$class->gen_xs_abort($builder);
return $builder;
}
sub gen_stream_registry {
my ($class, $builder, $max) = @_;
$builder->comment('Stream registry - O(1) lookup by fd')
->line('#define STREAM_MAX ' . $max)
->line('#define STREAM_STATE_INIT 0')
->line('#define STREAM_STATE_STARTED 1')
->line('#define STREAM_STATE_FINISHED 2')
->line('#define STREAM_STATE_ABORTED 3')
->blank
->line('typedef struct {')
->line(' int state;')
->line(' int chunks_sent;')
->line(' int http2;')
->line(' int status;')
->line(' char content_type[128];')
->line(' char extra_headers[512];') # For Cache-Control, X-Accel-Buffering, etc.
->line('} StreamState;')
->blank
->line('static StreamState stream_registry[STREAM_MAX];')
->blank;
}
sub gen_status_text {
my ($class, $builder) = @_;
$builder->line('static const char* stream_status_text(int status) {')
->line(' switch(status) {')
->line(' case 200: return "OK";')
->line(' case 201: return "Created";')
->line(' case 204: return "No Content";')
->line(' case 400: return "Bad Request";')
->line(' case 404: return "Not Found";')
->line(' case 500: return "Internal Server Error";')
->line(' default: return "OK";')
->line(' }')
->line('}')
->blank;
}
sub gen_stream_start_c {
my ($class, $builder) = @_;
$builder->line('static void stream_start_http1(int fd) {')
->line(' StreamState* s = &stream_registry[fd];')
->line(' char headers[2048];')
->line(' int len = snprintf(headers, sizeof(headers),')
->line(' "HTTP/1.1 %d %s\\r\\n"')
->line(' "Content-Type: %s\\r\\n"')
->line(' "%s"') # Extra headers (Cache-Control, etc.)
->line(' "Transfer-Encoding: chunked\\r\\n"')
->line(' "Connection: keep-alive\\r\\n\\r\\n",')
->line(' s->status, stream_status_text(s->status), s->content_type, s->extra_headers);')
->line(' send(fd, headers, len, 0);')
->line(' s->state = STREAM_STATE_STARTED;')
->line(' s->chunks_sent = 0;')
->line('}')
->blank;
}
sub gen_stream_write_chunk_c {
my ($class, $builder) = @_;
$builder->line('static void stream_write_chunk_http1(int fd, const char* data, size_t len) {')
->line(' if (len == 0) return;')
->line(' char size_line[32];')
->line(' int header_len = snprintf(size_line, sizeof(size_line), "%zx\\r\\n", len);')
->raw(<<'C')
#ifdef _WIN32
/* No writev on Windows; three send() calls instead. The chunk
* size line is tiny and the trailing CRLF is 2 bytes so the
* extra syscalls are negligible. */
send(fd, size_line, header_len, 0);
send(fd, data, len, 0);
send(fd, "\r\n", 2, 0);
#else
struct iovec iov[3];
iov[0].iov_base = size_line;
iov[0].iov_len = header_len;
iov[1].iov_base = (void*)data;
iov[1].iov_len = len;
iov[2].iov_base = "\r\n";
iov[2].iov_len = 2;
writev(fd, iov, 3);
#endif
C
->line(' stream_registry[fd].chunks_sent++;')
->line('}')
->blank;
}
sub gen_stream_end_c {
my ($class, $builder) = @_;
$builder->line('static void stream_end_http1(int fd) {')
->line(' send(fd, "0\\r\\n\\r\\n", 5, 0);')
->line(' stream_registry[fd].state = STREAM_STATE_FINISHED;')
->line('}')
->blank;
}
sub gen_stream_reset_c {
my ($class, $builder) = @_;
$builder->line('static void stream_reset(int fd) {')
->line(' memset(&stream_registry[fd], 0, sizeof(StreamState));')
->line(' stream_registry[fd].status = 200;')
->line(' strcpy(stream_registry[fd].content_type, "text/plain");')
->line('}')
->blank;
}
( run in 0.604 second using v1.01-cache-2.11-cpan-5a3173703d6 )