trunk/src/emu/webengine.c
| r30821 | r30822 | |
| 236 | 236 | } |
| 237 | 237 | else if (!strncmp(conn->uri, "/screenshot.png",15)) |
| 238 | 238 | { |
| 239 | | FILE *fp = (FILE *) conn->connection_param; |
| 240 | | char buf[200]; |
| 241 | | size_t n = 0; |
| 242 | | if (fp == NULL) |
| 239 | screen_device_iterator iter(m_machine->root_device()); |
| 240 | screen_device *screen = iter.first(); |
| 241 | |
| 242 | if (screen == NULL) |
| 243 | 243 | { |
| 244 | | screen_device_iterator iter(m_machine->root_device()); |
| 245 | | screen_device *screen = iter.first(); |
| 244 | return 0; |
| 245 | } |
| 246 | 246 | |
| 247 | | if (screen == NULL) |
| 248 | | { |
| 249 | | return 0; |
| 250 | | } |
| 247 | astring fname("screenshot.png"); |
| 248 | emu_file file(m_machine->options().snapshot_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); |
| 249 | file_error filerr = file.open(fname); |
| 251 | 250 | |
| 252 | | astring fname("screenshot.png"); |
| 253 | | { |
| 254 | | emu_file file(m_machine->options().snapshot_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS); |
| 255 | | file_error filerr = file.open(fname); |
| 256 | | |
| 257 | | if (filerr != FILERR_NONE) |
| 258 | | { |
| 259 | | return 0; |
| 260 | | } |
| 261 | | |
| 262 | | m_machine->video().save_snapshot(screen, file); |
| 263 | | astring fullpath(file.fullpath()); |
| 264 | | file.close(); |
| 265 | | } |
| 266 | | |
| 267 | | { |
| 268 | | emu_file file(m_machine->options().snapshot_directory(), OPEN_FLAG_READ); |
| 269 | | file_error filerr = file.open(fname); |
| 270 | | |
| 271 | | if (filerr != FILERR_NONE) |
| 272 | | { |
| 273 | | return 0; |
| 274 | | } |
| 275 | | |
| 276 | | file.seek(0, SEEK_SET); |
| 277 | | mg_send_header(conn, "Content-Type", "image/png"); |
| 278 | | mg_send_header(conn, "Cache-Control", "no-cache, no-store, must-revalidate"); |
| 279 | | mg_send_header(conn, "Pragma", "no-cache"); |
| 280 | | mg_send_header(conn, "Expires", "0"); |
| 281 | | do |
| 282 | | { |
| 283 | | n = file.read(buf, sizeof(buf)); |
| 284 | | mg_send_data(conn, buf, n); |
| 285 | | } |
| 286 | | while (n==sizeof(buf)); |
| 287 | | file.close(); |
| 288 | | } |
| 251 | if (filerr != FILERR_NONE) |
| 252 | { |
| 253 | return 0; |
| 289 | 254 | } |
| 290 | | return MG_TRUE; |
| 255 | |
| 256 | m_machine->video().save_snapshot(screen, file); |
| 257 | astring fullpath(file.fullpath()); |
| 258 | file.close(); |
| 259 | mg_send_header(conn, "Cache-Control", "no-cache, no-store, must-revalidate"); |
| 260 | mg_send_header(conn, "Pragma", "no-cache"); |
| 261 | mg_send_header(conn, "Expires", "0"); |
| 262 | mg_send_file(conn, fullpath.cstr()); |
| 263 | return MG_MORE; // It is important to return MG_MORE after mg_send_file! |
| 291 | 264 | } |
| 292 | 265 | return 0; |
| 293 | 266 | } |
trunk/src/lib/web/mongoose.c
| r30821 | r30822 | |
| 337 | 337 | (void) pthread_attr_init(&attr); |
| 338 | 338 | (void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); |
| 339 | 339 | |
| 340 | | #ifdef NS_STACK_SIZE |
| 341 | 340 | #if NS_STACK_SIZE > 1 |
| 342 | 341 | (void) pthread_attr_setstacksize(&attr, NS_STACK_SIZE); |
| 343 | 342 | #endif |
| 344 | | #endif |
| 345 | 343 | |
| 346 | 344 | pthread_create(&thread_id, &attr, f, p); |
| 347 | 345 | pthread_attr_destroy(&attr); |
| r30821 | r30822 | |
| 807 | 805 | iobuf_remove(io, n); |
| 808 | 806 | } |
| 809 | 807 | |
| 810 | | if (io->len == 0 && conn->flags & NSF_FINISHED_SENDING_DATA) { |
| 808 | if (io->len == 0 && (conn->flags & NSF_FINISHED_SENDING_DATA)) { |
| 811 | 809 | conn->flags |= NSF_CLOSE_IMMEDIATELY; |
| 812 | 810 | } |
| 813 | 811 | } |
| r30821 | r30822 | |
| 1604 | 1602 | ns_send(conn->ns_conn, "\r\n", 2); |
| 1605 | 1603 | } |
| 1606 | 1604 | |
| 1607 | | int mg_printf(struct mg_connection *conn, const char *fmt, ...) { |
| 1605 | size_t mg_printf(struct mg_connection *conn, const char *fmt, ...) { |
| 1608 | 1606 | struct connection *c = MG_CONN_2_CONN(conn); |
| 1609 | | int len; |
| 1610 | 1607 | va_list ap; |
| 1611 | 1608 | |
| 1612 | 1609 | va_start(ap, fmt); |
| 1613 | | len = ns_vprintf(c->ns_conn, fmt, ap); |
| 1610 | ns_vprintf(c->ns_conn, fmt, ap); |
| 1614 | 1611 | va_end(ap); |
| 1615 | 1612 | |
| 1616 | | return len; |
| 1613 | return c->ns_conn->send_iobuf.len; |
| 1617 | 1614 | } |
| 1618 | 1615 | |
| 1619 | 1616 | static void ns_forward(struct ns_connection *from, struct ns_connection *to) { |
| r30821 | r30822 | |
| 2178 | 2175 | n = (int) strlen(ri->uri); |
| 2179 | 2176 | mg_url_decode(ri->uri, n, (char *) ri->uri, n + 1, 0); |
| 2180 | 2177 | if (*ri->uri == '/' || *ri->uri == '.') { |
| 2181 | | remove_double_dots_and_double_slashes((char *) ri->uri); |
| 2178 | remove_double_dots_and_double_slashes((char *) ri->uri); |
| 2182 | 2179 | } |
| 2183 | 2180 | } |
| 2184 | 2181 | |
| r30821 | r30822 | |
| 2378 | 2375 | (header == NULL && http_version && !strcmp(http_version, "1.1"))); |
| 2379 | 2376 | } |
| 2380 | 2377 | |
| 2381 | | int mg_write(struct mg_connection *c, const void *buf, int len) { |
| 2378 | size_t mg_write(struct mg_connection *c, const void *buf, int len) { |
| 2382 | 2379 | struct connection *conn = MG_CONN_2_CONN(c); |
| 2383 | | return ns_send(conn->ns_conn, buf, len); |
| 2380 | ns_send(conn->ns_conn, buf, len); |
| 2381 | return conn->ns_conn->send_iobuf.len; |
| 2384 | 2382 | } |
| 2385 | 2383 | |
| 2386 | 2384 | void mg_send_status(struct mg_connection *c, int status) { |
| r30821 | r30822 | |
| 2407 | 2405 | } |
| 2408 | 2406 | } |
| 2409 | 2407 | |
| 2410 | | void mg_send_data(struct mg_connection *c, const void *data, int data_len) { |
| 2408 | size_t mg_send_data(struct mg_connection *c, const void *data, int data_len) { |
| 2409 | struct connection *conn = MG_CONN_2_CONN(c); |
| 2411 | 2410 | terminate_headers(c); |
| 2412 | 2411 | write_chunk(MG_CONN_2_CONN(c), (const char *) data, data_len); |
| 2412 | return conn->ns_conn->send_iobuf.len; |
| 2413 | 2413 | } |
| 2414 | 2414 | |
| 2415 | | void mg_printf_data(struct mg_connection *c, const char *fmt, ...) { |
| 2415 | size_t mg_printf_data(struct mg_connection *c, const char *fmt, ...) { |
| 2416 | 2416 | struct connection *conn = MG_CONN_2_CONN(c); |
| 2417 | 2417 | va_list ap; |
| 2418 | 2418 | int len; |
| r30821 | r30822 | |
| 2430 | 2430 | if (buf != mem && buf != NULL) { |
| 2431 | 2431 | free(buf); |
| 2432 | 2432 | } |
| 2433 | return conn->ns_conn->send_iobuf.len; |
| 2433 | 2434 | } |
| 2434 | 2435 | |
| 2435 | 2436 | #if !defined(MONGOOSE_NO_WEBSOCKET) || !defined(MONGOOSE_NO_AUTH) |
| r30821 | r30822 | |
| 2662 | 2663 | return buffered; |
| 2663 | 2664 | } |
| 2664 | 2665 | |
| 2665 | | int mg_websocket_write(struct mg_connection* conn, int opcode, |
| 2666 | size_t mg_websocket_write(struct mg_connection* conn, int opcode, |
| 2666 | 2667 | const char *data, size_t data_len) { |
| 2667 | 2668 | unsigned char mem[4192], *copy = mem; |
| 2668 | 2669 | size_t copy_len = 0; |
| 2669 | | int retval = -1; |
| 2670 | 2670 | |
| 2671 | 2671 | if (data_len + 10 > sizeof(mem) && |
| 2672 | 2672 | (copy = (unsigned char *) malloc(data_len + 10)) == NULL) { |
| 2673 | | return -1; |
| 2673 | return 0; |
| 2674 | 2674 | } |
| 2675 | 2675 | |
| 2676 | 2676 | copy[0] = 0x80 + (opcode & 0x0f); |
| r30821 | r30822 | |
| 2698 | 2698 | } |
| 2699 | 2699 | |
| 2700 | 2700 | if (copy_len > 0) { |
| 2701 | | retval = mg_write(conn, copy, copy_len); |
| 2701 | mg_write(conn, copy, copy_len); |
| 2702 | 2702 | } |
| 2703 | 2703 | if (copy != mem) { |
| 2704 | 2704 | free(copy); |
| 2705 | 2705 | } |
| 2706 | 2706 | |
| 2707 | | return retval; |
| 2707 | return MG_CONN_2_CONN(conn)->ns_conn->send_iobuf.len; |
| 2708 | 2708 | } |
| 2709 | 2709 | |
| 2710 | | int mg_websocket_printf(struct mg_connection* conn, int opcode, |
| 2711 | | const char *fmt, ...) { |
| 2710 | size_t mg_websocket_printf(struct mg_connection* conn, int opcode, |
| 2711 | const char *fmt, ...) { |
| 2712 | 2712 | char mem[4192], *buf = mem; |
| 2713 | 2713 | va_list ap; |
| 2714 | 2714 | int len; |
| r30821 | r30822 | |
| 2723 | 2723 | free(buf); |
| 2724 | 2724 | } |
| 2725 | 2725 | |
| 2726 | | return len; |
| 2726 | return MG_CONN_2_CONN(conn)->ns_conn->send_iobuf.len; |
| 2727 | 2727 | } |
| 2728 | 2728 | |
| 2729 | 2729 | static void send_websocket_handshake_if_requested(struct mg_connection *conn) { |
| r30821 | r30822 | |
| 4123 | 4123 | } |
| 4124 | 4124 | } |
| 4125 | 4125 | |
| 4126 | | static void open_local_endpoint(struct connection *conn, int skip_user) { |
| 4127 | 4126 | #ifndef MONGOOSE_NO_FILESYSTEM |
| 4127 | void mg_send_file(struct mg_connection *c, const char *file_name) { |
| 4128 | struct connection *conn = MG_CONN_2_CONN(c); |
| 4128 | 4129 | file_stat_t st; |
| 4129 | 4130 | char path[MAX_PATH_SIZE]; |
| 4130 | 4131 | int exists = 0, is_directory = 0; |
| r30821 | r30822 | |
| 4138 | 4139 | #else |
| 4139 | 4140 | const char *dir_lst = "yes"; |
| 4140 | 4141 | #endif |
| 4142 | |
| 4143 | mg_snprintf(path, sizeof(path), "%s", file_name); |
| 4144 | exists = stat(path, &st) == 0; |
| 4145 | is_directory = S_ISDIR(st.st_mode); |
| 4146 | |
| 4147 | if (!exists || must_hide_file(conn, path)) { |
| 4148 | send_http_error(conn, 404, NULL); |
| 4149 | } else if (is_directory && |
| 4150 | conn->mg_conn.uri[strlen(conn->mg_conn.uri) - 1] != '/') { |
| 4151 | conn->mg_conn.status_code = 301; |
| 4152 | mg_printf(&conn->mg_conn, "HTTP/1.1 301 Moved Permanently\r\n" |
| 4153 | "Location: %s/\r\n\r\n", conn->mg_conn.uri); |
| 4154 | close_local_endpoint(conn); |
| 4155 | } else if (is_directory && !find_index_file(conn, path, sizeof(path), &st)) { |
| 4156 | if (!mg_strcasecmp(dir_lst, "yes")) { |
| 4157 | #ifndef MONGOOSE_NO_DIRECTORY_LISTING |
| 4158 | send_directory_listing(conn, path); |
| 4159 | #else |
| 4160 | send_http_error(conn, 501, NULL); |
| 4141 | 4161 | #endif |
| 4162 | } else { |
| 4163 | send_http_error(conn, 403, NULL); |
| 4164 | } |
| 4165 | } else if (mg_match_prefix(cgi_pat, strlen(cgi_pat), path) > 0) { |
| 4166 | #if !defined(MONGOOSE_NO_CGI) |
| 4167 | open_cgi_endpoint(conn, path); |
| 4168 | #else |
| 4169 | send_http_error(conn, 501, NULL); |
| 4170 | #endif // !MONGOOSE_NO_CGI |
| 4171 | #ifndef MONGOOSE_NO_SSI |
| 4172 | } else if (mg_match_prefix(conn->server->config_options[SSI_PATTERN], |
| 4173 | strlen(conn->server->config_options[SSI_PATTERN]), |
| 4174 | path) > 0) { |
| 4175 | handle_ssi_request(conn, path); |
| 4176 | #endif |
| 4177 | } else if (is_not_modified(conn, &st)) { |
| 4178 | send_http_error(conn, 304, NULL); |
| 4179 | } else if ((conn->endpoint.fd = open(path, O_RDONLY | O_BINARY)) != -1) { |
| 4180 | // O_BINARY is required for Windows, otherwise in default text mode |
| 4181 | // two bytes \r\n will be read as one. |
| 4182 | open_file_endpoint(conn, path, &st); |
| 4183 | } else { |
| 4184 | send_http_error(conn, 404, NULL); |
| 4185 | } |
| 4186 | } |
| 4187 | #endif // !MONGOOSE_NO_FILESYSTEM |
| 4142 | 4188 | |
| 4189 | static void open_local_endpoint(struct connection *conn, int skip_user) { |
| 4190 | char path[MAX_PATH_SIZE]; |
| 4191 | file_stat_t st; |
| 4192 | int exists = 0; |
| 4193 | |
| 4143 | 4194 | // If EP_USER was set in a prev call, reset it |
| 4144 | 4195 | conn->endpoint_type = EP_NONE; |
| 4145 | 4196 | |
| r30821 | r30822 | |
| 4172 | 4223 | proxify_connection(conn); |
| 4173 | 4224 | return; |
| 4174 | 4225 | } |
| 4175 | | |
| 4176 | | #ifdef MONGOOSE_NO_FILESYSTEM |
| 4226 | |
| 4177 | 4227 | if (!strcmp(conn->mg_conn.request_method, "OPTIONS")) { |
| 4178 | 4228 | send_options(conn); |
| 4179 | | } else { |
| 4180 | | send_http_error(conn, 404, NULL); |
| 4229 | return; |
| 4181 | 4230 | } |
| 4231 | |
| 4232 | #ifdef MONGOOSE_NO_FILESYSTEM |
| 4233 | send_http_error(conn, 404, NULL); |
| 4182 | 4234 | #else |
| 4183 | 4235 | exists = convert_uri_to_file_name(conn, path, sizeof(path), &st); |
| 4184 | | is_directory = S_ISDIR(st.st_mode); |
| 4185 | 4236 | |
| 4186 | 4237 | if (!strcmp(conn->mg_conn.request_method, "OPTIONS")) { |
| 4187 | 4238 | send_options(conn); |
| r30821 | r30822 | |
| 4203 | 4254 | } else if (!strcmp(conn->mg_conn.request_method, "PUT")) { |
| 4204 | 4255 | handle_put(conn, path); |
| 4205 | 4256 | #endif |
| 4206 | | } else if (!exists || must_hide_file(conn, path)) { |
| 4207 | | send_http_error(conn, 404, NULL); |
| 4208 | | } else if (is_directory && |
| 4209 | | conn->mg_conn.uri[strlen(conn->mg_conn.uri) - 1] != '/') { |
| 4210 | | conn->mg_conn.status_code = 301; |
| 4211 | | mg_printf(&conn->mg_conn, "HTTP/1.1 301 Moved Permanently\r\n" |
| 4212 | | "Location: %s/\r\n\r\n", conn->mg_conn.uri); |
| 4213 | | close_local_endpoint(conn); |
| 4214 | | } else if (is_directory && !find_index_file(conn, path, sizeof(path), &st)) { |
| 4215 | | if (!mg_strcasecmp(dir_lst, "yes")) { |
| 4216 | | #ifndef MONGOOSE_NO_DIRECTORY_LISTING |
| 4217 | | send_directory_listing(conn, path); |
| 4218 | | #else |
| 4219 | | send_http_error(conn, 501, NULL); |
| 4220 | | #endif |
| 4221 | | } else { |
| 4222 | | send_http_error(conn, 403, NULL); |
| 4223 | | } |
| 4224 | | } else if (mg_match_prefix(cgi_pat, strlen(cgi_pat), path) > 0) { |
| 4225 | | #if !defined(MONGOOSE_NO_CGI) |
| 4226 | | open_cgi_endpoint(conn, path); |
| 4227 | | #else |
| 4228 | | send_http_error(conn, 501, NULL); |
| 4229 | | #endif // !MONGOOSE_NO_CGI |
| 4230 | | #ifndef MONGOOSE_NO_SSI |
| 4231 | | } else if (mg_match_prefix(conn->server->config_options[SSI_PATTERN], |
| 4232 | | strlen(conn->server->config_options[SSI_PATTERN]), |
| 4233 | | path) > 0) { |
| 4234 | | handle_ssi_request(conn, path); |
| 4235 | | #endif |
| 4236 | | } else if (is_not_modified(conn, &st)) { |
| 4237 | | send_http_error(conn, 304, NULL); |
| 4238 | | } else if ((conn->endpoint.fd = open(path, O_RDONLY | O_BINARY)) != -1) { |
| 4239 | | // O_BINARY is required for Windows, otherwise in default text mode |
| 4240 | | // two bytes \r\n will be read as one. |
| 4241 | | open_file_endpoint(conn, path, &st); |
| 4242 | 4257 | } else { |
| 4243 | | send_http_error(conn, 404, NULL); |
| 4258 | mg_send_file(&conn->mg_conn, path); |
| 4244 | 4259 | } |
| 4245 | 4260 | #endif // MONGOOSE_NO_FILESYSTEM |
| 4246 | 4261 | } |
| r30821 | r30822 | |
| 4496 | 4511 | |
| 4497 | 4512 | static void transfer_file_data(struct connection *conn) { |
| 4498 | 4513 | char buf[IOBUF_SIZE]; |
| 4499 | | int n = read(conn->endpoint.fd, buf, conn->cl < (int64_t) sizeof(buf) ? |
| 4500 | | (int) conn->cl : (int) sizeof(buf)); |
| 4514 | int n; |
| 4501 | 4515 | |
| 4516 | // If output buffer is too big, don't send anything. Wait until |
| 4517 | // mongoose drains already buffered data to the client. |
| 4518 | if (conn->ns_conn->send_iobuf.len > sizeof(buf) * 2) return; |
| 4519 | |
| 4520 | // Do not send anyt |
| 4521 | n = read(conn->endpoint.fd, buf, conn->cl < (int64_t) sizeof(buf) ? |
| 4522 | (int) conn->cl : (int) sizeof(buf)); |
| 4523 | |
| 4502 | 4524 | if (n <= 0) { |
| 4503 | 4525 | close_local_endpoint(conn); |
| 4504 | 4526 | } else if (n > 0) { |