summaryrefslogtreecommitdiff
path: root/c/wasi-http/echo-request/component.c
blob: 6f4c626dcb47e9e033730386edffb80dca30fe55 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
/* SPDX-License-Identifier: Apache-2.0 */

/*
 * component.c - Example of writing a wasi-http Wasm component
 *
 * Copyright (C) Andrew Clayton
 * Copyright (C) F5, Inc.
 */

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <stdint.h>
#include <string.h>

#include "proxy.h"

#define ex(...) \
	do { \
		printf(__VA_ARGS__); \
		exit(EXIT_FAILURE); \
	} while (0);

static const struct {
	const char *method;
} http_method_map[] = {
	[WASI_HTTP_TYPES_METHOD_GET]	 = { "GET"     },
	[WASI_HTTP_TYPES_METHOD_HEAD]	 = { "HEAD"    },
	[WASI_HTTP_TYPES_METHOD_POST]    = { "POST"    },
	[WASI_HTTP_TYPES_METHOD_PUT]	 = { "PUT"     },
	[WASI_HTTP_TYPES_METHOD_DELETE]	 = { "DELETE"  },
	[WASI_HTTP_TYPES_METHOD_CONNECT] = { "CONNECT" },
	[WASI_HTTP_TYPES_METHOD_OPTIONS] = { "OPTIONS" },
	[WASI_HTTP_TYPES_METHOD_TRACE]	 = { "TRACE"   },
	[WASI_HTTP_TYPES_METHOD_PATCH]   = { "PATCH"   },
	[WASI_HTTP_TYPES_METHOD_OTHER]	 = { "OTHER"   }
};

void exports_wasi_http_incoming_handler_handle(
	exports_wasi_http_incoming_handler_own_incoming_request_t request,
	exports_wasi_http_incoming_handler_own_response_outparam_t response_out)
{
	bool ok;
	FILE *out;
	size_t size;
	char *out_ptr;
	char *ptr;
	char clen[32];
	wasi_http_types_borrow_incoming_request_t b_req;
	wasi_http_types_own_headers_t hdrs;
	wasi_http_types_borrow_fields_t b_hdrs;
	wasi_http_types_own_incoming_body_t r_body;
	wasi_http_types_borrow_incoming_body_t b_r_body;
	wasi_http_types_own_outgoing_response_t resp;
	wasi_http_types_borrow_outgoing_response_t b_resp;
	wasi_http_types_own_fields_t fields;
	wasi_http_types_borrow_fields_t b_fields;
	wasi_http_types_result_own_outgoing_response_error_code_t rerr = { };
	wasi_http_types_own_outgoing_body_t body;
	wasi_http_types_borrow_outgoing_body_t b_body;
	wasi_io_streams_own_output_stream_t out_stream;
	wasi_io_streams_borrow_output_stream_t b_out_stream;
	proxy_list_u8_t stream_data;
	wasi_io_streams_stream_error_t stream_err;
	wasi_http_types_header_error_t hdr_err;
	wasi_http_types_field_key_t key;
	wasi_http_types_field_value_t value;
	wasi_http_types_method_t method;
	proxy_list_tuple2_field_key_field_value_t fvk;
	wasi_http_types_own_input_stream_t in_stream;
	wasi_io_streams_borrow_input_stream_t b_in_stream;
	proxy_list_u8_t data;
	wasi_io_streams_stream_error_t in_stream_err;
	proxy_string_t prstr;

	b_req = wasi_http_types_borrow_incoming_request(request);

	out = open_memstream(&out_ptr, &size);

#define BUF_ADD(fmt, ...) \
	fprintf(out, fmt, ##__VA_ARGS__);

	BUF_ADD("*** Welcome to WebAssembly with wasi-http / C ***\n\n");

	BUF_ADD("[Request Info]\n");
	wasi_http_types_method_incoming_request_path_with_query(b_req, &prstr);
	BUF_ADD("REQUEST_PATH = %.*s\n", (int)prstr.len, prstr.ptr);
	wasi_http_types_method_incoming_request_method(b_req, &method);
	BUF_ADD("METHOD       = %s\n", http_method_map[method.tag].method);
	ptr = memchr(prstr.ptr, '?', prstr.len);
	BUF_ADD("QUERY        = %.*s\n",
		ptr ? (int)(((char *)(prstr.ptr + prstr.len)) - ptr - 1) : 0,
		ptr ? ptr + 1 : "");

	BUF_ADD("\n[Request Headers]\n");
	hdrs = wasi_http_types_method_incoming_request_headers(b_req);
	b_hdrs = wasi_http_types_borrow_fields(hdrs);

	wasi_http_types_method_fields_entries(b_hdrs, &fvk);
	for (size_t i = 0; i < fvk.len; i++)
		BUF_ADD("%.*s = %.*s\n",
			(int)fvk.ptr[i].f0.len, fvk.ptr[i].f0.ptr,
			(int)fvk.ptr[i].f1.len, fvk.ptr[i].f1.ptr);

	proxy_list_tuple2_field_key_field_value_free(&fvk);

	ok = wasi_http_types_method_incoming_request_consume(b_req, &r_body);
	if (!ok)
		ex("wasi_http_types_method_incoming_request_consume() failed\n");
	b_r_body = wasi_http_types_borrow_incoming_body(r_body);
	ok = wasi_http_types_method_incoming_body_stream(b_r_body, &in_stream);
	if (!ok)
		ex("wasi_http_types_method_incoming_body_stream() failed\n");
	b_in_stream = wasi_io_streams_borrow_input_stream(in_stream);

	ok = wasi_io_streams_method_input_stream_blocking_read(b_in_stream,
							       8 * 1024*1024,
							       &data,
							       &in_stream_err);

	if (method.tag == WASI_HTTP_TYPES_METHOD_POST ||
	    method.tag == WASI_HTTP_TYPES_METHOD_PUT) {
		BUF_ADD("\n[%s data]\n",
			http_method_map[method.tag].method);
		BUF_ADD("%.*s\n", (int)data.len, data.ptr);
	}

	fclose(out);

	fields = wasi_http_types_constructor_fields();
	b_fields = wasi_http_types_borrow_fields(fields);

	proxy_string_set((proxy_string_t *)&key, "Content-Length");
	sprintf(clen, "%zu", size);
	proxy_string_set((proxy_string_t *)&value, clen);

	ok = wasi_http_types_method_fields_append(b_fields, &key, &value,
						  &hdr_err);
	if (!ok)
		ex("wasi_http_types_method_fields_append() failed\n");

	resp = wasi_http_types_constructor_outgoing_response(fields);

	b_resp = wasi_http_types_borrow_outgoing_response(resp);
	ok = wasi_http_types_method_outgoing_response_body(b_resp, &body);
	if (!ok)
		ex("wasi_http_types_method_outgoing_response_body() failed\n");
	b_body = wasi_http_types_borrow_outgoing_body(body);

	ok = wasi_http_types_method_outgoing_body_write(b_body, &out_stream);
	if (!ok)
		ex("wasi_http_types_method_outgoing_body_write() failed\n");
	b_out_stream = wasi_io_streams_borrow_output_stream(out_stream);

	stream_data.len = size;
	stream_data.ptr = (uint8_t *)out_ptr;
	ok = wasi_io_streams_method_output_stream_blocking_write_and_flush(
								b_out_stream,
								&stream_data,
								&stream_err);
	if (!ok)
		ex("wasi_io_streams_method_output_stream_blocking_write_and_flush() failed\n");

	free(out_ptr);

	wasi_http_types_static_response_outparam_set(response_out, &rerr);
}