📄 http.c
字号:
/* * Copyright (C) 2004 Nathan Lutchansky <lutchann@litech.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */#include <sys/types.h>#include <stdlib.h>#include <stdio.h>#include <string.h>#include <unistd.h>#include <fcntl.h>#include <errno.h>#include <sys/time.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <event.h>#include <log.h>#include <frame.h>#include <stream.h>#include <pmsg.h>#include <rtp.h>#include <conf_parse.h>void write_access_log( char *path, struct sockaddr *addr, int code, char *req, int length, char *referer, char *user_agent );struct http_stream_session;struct http_location { struct loc_node node; struct stream_destination *input; struct frame *frame; int length_with_jfif; struct http_stream_session *sess_list; int streaming;};struct http_stream_session { struct http_stream_session *next; struct http_stream_session *prev; struct http_location *loc; struct conn *conn;};static struct http_location *http_loc_list = NULL;static struct loc_node *node_find_location( struct loc_node *list, char *path, int len ){ struct loc_node *loc; for( loc = list; loc; loc = loc->next ) if( ! strncmp( path, loc->path, strlen( loc->path ) ) && ( loc->path[len] == '/' || loc->path[len] == 0 ) ) return loc; return NULL;}static struct http_location *find_http_location( char *path ){ int len; len = strlen( path ); if( path[len - 1] == '/' ) --len; return (struct http_location *)node_find_location( (struct loc_node *)http_loc_list, path, len );}static void init_location( struct loc_node *node, char *path, struct loc_node **list ){ node->next = *list; node->prev = NULL; if( node->next ) node->next->prev = node; *list = node; strcpy( node->path, path );}static void log_request( struct req *req, int code, int length ){ char *ref, *ua; ref = get_header( req->req, "referer" ); ua = get_header( req->req, "user-agent" ); write_access_log( NULL, (struct sockaddr *)&req->conn->client_addr, code, req->conn->req_buf, length, ref ? ref : "-", ua ? ua : "-" );}static void http_create_reply( struct req *req, int code, char *reply ){ req->resp = new_pmsg( 512 ); req->resp->type = PMSG_RESP; req->resp->proto_id = add_pmsg_string( req->resp, "HTTP/1.0" ); req->resp->sl.stat.code = code; req->resp->sl.stat.reason = add_pmsg_string( req->resp, reply );}static void http_send_error( struct req *req, int code, char *reply, char *t ){ log_request( req, code, 0 ); http_create_reply( req, code, reply ); add_header( req->resp, "Connection", "close" ); add_header( req->resp, "Content-Type", "text/html" ); req->conn->drop_after = 1; if( tcp_send_pmsg( req->conn, req->resp, strlen( t ) ) >= 0 ) send_data( req->conn, t, strlen( t ) );}void http_conn_disconnect( struct conn *c ){ struct http_stream_session *s = (struct http_stream_session *)c->proto_state; if( s->next ) s->next->prev = s->prev; if( s->prev ) s->prev->next = s->next; else s->loc->sess_list = s->next; free( s );}static void add_http_stream_session( struct http_location *loc, struct conn *c ){ struct http_stream_session *s; s = (struct http_stream_session *) malloc( sizeof( struct http_stream_session ) ); s->next = loc->sess_list; s->prev = NULL; if( s->next ) s->next->prev = s; loc->sess_list = s; s->loc = loc; s->conn = c; c->proto_state = s;}static void send_frame_with_jfif( struct http_location *loc, struct conn *c ){ static unsigned char add_jfif[] = { 0xff, 0xd8, 0xff, 0xe0, 0x00, 0x10, 0x4a, 0x46, 0x49, 0x46, 0x00, 0x01, 0x02, 0x01, 0x00, 0x48, 0x00, 0x48, 0x00, 0x00 }; if( loc->length_with_jfif > loc->frame->length ) { send_data( c, add_jfif, 20 ); send_data( c, loc->frame->d + 2, loc->frame->length - 2 ); } else send_data( c, loc->frame->d, loc->frame->length );}static void send_multipart_frame( struct http_location *loc, struct conn *c ){ char hdrs[128]; int hlen; hlen = sprintf( hdrs, "--boundary\r\nContent-Type: image/jpeg\r\nContent-Length: %d\r\n\r\n", loc->length_with_jfif ); if( avail_send_buf( c ) < loc->length_with_jfif + hlen ) return; send_data( c, hdrs, hlen ); send_frame_with_jfif( loc, c );}static int handle_GET( struct req *req ){ struct http_location *loc; loc = find_http_location( req->req->sl.req.uri ); if( ! loc || strlen( req->req->sl.req.uri ) > strlen( loc->node.path ) ) { http_send_error( req, 404, "Not Found", "<html><body><p>File not found</p></body></html>" ); return 0; } if( ! loc->frame || avail_send_buf( req->conn ) < loc->frame->length + 400 ) { http_send_error( req, 404, "Not Found", "<html><body><p>Image not available</p></body></html>" ); return 0; } http_create_reply( req, 200, "OK" ); add_header( req->resp, "Expires", "0" ); add_header( req->resp, "Pragma", "no-cache" ); add_header( req->resp, "Cache-Control", "no-cache" ); if( loc->streaming ) { log_request( req, 200, 0 ); add_header( req->resp, "Content-Type", "multipart/x-mixed-replace;boundary=\"boundary\"" ); tcp_send_pmsg( req->conn, req->resp, -1 ); add_http_stream_session( loc, req->conn ); send_multipart_frame( loc, req->conn ); } else { log_request( req, 200, loc->frame->length ); add_header( req->resp, "Connection", "close" ); add_header( req->resp, "Content-Type", "image/jpeg" ); req->conn->drop_after = 1; if( tcp_send_pmsg( req->conn, req->resp, loc->length_with_jfif ) >= 0 ) send_frame_with_jfif( loc, req->conn ); } //send_data( req->conn, rep, sprintf( rep, "HTTP/1.0 200 OK\r\nConnection: close\r\nContent-Type: multipart/x-mixed-replace;boundary=\"boundary\"\r\n\r\n--boundary\r\nContent-Type: image/jpeg\r\nContent-Length: %d\r\n\r\n", loc->frame->length ) ); //send_data( req->conn, loc->frame->d, loc->frame->length ); return 0;}static int handle_unknown( struct req *req ){ http_send_error( req, 501, "Not Implemented", "<html><body><p>POST requests are unsupported here</p></body></html>" ); return 0;}int http_handle_msg( struct req *req ){ int ret; if( ! strcasecmp( req->req->sl.req.method, "GET" ) ) ret = handle_GET( req ); else ret = handle_unknown( req ); return ret;}static void jpeg_next_frame( struct frame *f, void *d ){ struct http_location *loc = (struct http_location *)d; struct http_stream_session *s; if( f->d[0] != 0xff || f->d[1] != 0xd8 || f->d[2] != 0xff ) { spook_log( SL_WARN, "http: received a malformed JPEG frame" ); unref_frame( f ); return; } if( loc->frame ) unref_frame( loc->frame ); loc->frame = f; loc->length_with_jfif = f->length; if( f->d[3] != 0xe0 || f->d[10] != 0 || strcmp( f->d + 6, "JFIF" ) ) loc->length_with_jfif += 18; for( s = loc->sess_list; s; s = s->next ) send_multipart_frame( loc, s->conn );}/************************ CONFIGURATION DIRECTIVES ************************/static void *start_block(void){ struct http_location *loc; loc = (struct http_location *)malloc( sizeof( struct http_location ) ); init_location( (struct loc_node *)loc, "", (struct loc_node **)&http_loc_list ); loc->input = NULL; loc->frame = NULL; loc->sess_list = NULL; loc->streaming = 0; return loc;}static int end_block( void *d ){ struct http_location *loc = (struct http_location *)d; if( ! loc->input ) { spook_log( SL_ERR, "http output: missing input stream name" ); return -1; } if( ! *loc->node.path ) { spook_log( SL_ERR, "http output: missing URL path" ); return -1; } set_waiting( loc->input, 1 ); return 0;}static int set_input( int num_tokens, struct token *tokens, void *d ){ struct http_location *loc = (struct http_location *)d; int format = FORMAT_JPEG; if( ! ( loc->input = connect_to_stream( tokens[1].v.str, jpeg_next_frame, loc, &format, 1 ) ) ) { spook_log( SL_ERR, "http output: unable to connect to stream \"%s\"", tokens[1].v.str ); return -1; } return 0;}static int set_path( int num_tokens, struct token *tokens, void *d ){ struct http_location *loc = (struct http_location *)d; strcpy( loc->node.path, tokens[1].v.str ); return 0;}static int set_mode( int num_tokens, struct token *tokens, void *d ){ struct http_location *loc = (struct http_location *)d; if( ! strcasecmp( tokens[1].v.str, "single" ) ) loc->streaming = 0; else if( ! strcasecmp( tokens[1].v.str, "stream" ) ) loc->streaming = 1; else { spook_log( SL_ERR, "http output: Mode must be 'single' or 'stream'" ); return -1; } return 0;}static struct statement config_statements[] = { /* directive name, process function, min args, max args, arg types */ { "input", set_input, 1, 1, { TOKEN_STR } }, { "path", set_path, 1, 1, { TOKEN_STR } }, { "mode", set_mode, 1, 1, { TOKEN_STR } }, /* empty terminator -- do not remove */ { NULL, NULL, 0, 0, {} }};int http_init(void){ register_config_context( "output", "http", start_block, end_block, config_statements ); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -