1175 lines
31 KiB
C++
1175 lines
31 KiB
C++
|
/* J. David's webserver */
|
|||
|
/* This is a simple webserver.
|
|||
|
* Created November 1999 by J. David Blackstone.
|
|||
|
* CSE 4344 (Network concepts), Prof. Zeigler
|
|||
|
* University of Texas at Arlington
|
|||
|
*/
|
|||
|
/* This program compiles for Sparc Solaris 2.6.
|
|||
|
* To compile for Linux:
|
|||
|
* 1) Comment out the #include <pthread.h> line.
|
|||
|
* 2) Comment out the line that defines the variable newthread.
|
|||
|
* 3) Comment out the two lines that run pthread_create().
|
|||
|
* 4) Uncomment the line that runs accept_request().
|
|||
|
* 5) Remove -lsocket from the Makefile.
|
|||
|
*/
|
|||
|
#include <stdio.h>
|
|||
|
#include <sys/socket.h>
|
|||
|
#include <sys/types.h>
|
|||
|
#include <netinet/in.h>
|
|||
|
#include <arpa/inet.h>
|
|||
|
#include <unistd.h>
|
|||
|
#include <ctype.h>
|
|||
|
#include <strings.h>
|
|||
|
#include <string.h>
|
|||
|
#include <sys/stat.h>
|
|||
|
#include <pthread.h>
|
|||
|
#include <sys/wait.h>
|
|||
|
#include <stdlib.h>
|
|||
|
#include <errno.h>
|
|||
|
|
|||
|
|
|||
|
#include "httpd.h"
|
|||
|
#define LOG_TAG "httpserver"
|
|||
|
#ifdef SDV
|
|||
|
#include <cutils/log.h>
|
|||
|
#warning "BUILD SDV HTTPD"
|
|||
|
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG , LOG_TAG, __VA_ARGS__)
|
|||
|
#else
|
|||
|
#define LOGD(...) printf(__VA_ARGS__)
|
|||
|
#endif
|
|||
|
typedef struct mime_typ {
|
|||
|
char ext[10];
|
|||
|
int ext_len;
|
|||
|
char value[50];
|
|||
|
} mime_typ_t;
|
|||
|
static mime_typ_t mime_tab[] = {
|
|||
|
{"txt", 3, "txt/plain"},
|
|||
|
{"ms", 2, "application/x-troff-ms"},
|
|||
|
{"ms", 2, "application/x-troff-ms"},
|
|||
|
{"mv", 2, "video/x-sgi-movie"},
|
|||
|
{"qt", 2, "video/quicktime"},
|
|||
|
{"ts", 2, "video/mp2t"},
|
|||
|
{"3gp", 3, "video/3gp"},
|
|||
|
{"asf", 3, "video/x-ms-asf"},
|
|||
|
{"avi", 3, "video/x-msvideo"},
|
|||
|
{"flv", 3, "video/x-flv"},
|
|||
|
{"vob", 3, "video/mpeg"},
|
|||
|
{"mkv", 3, "video/x-matroska"},
|
|||
|
{"mov", 3, "video/quicktime"},
|
|||
|
{"mp2", 3, "audio/mpeg"},
|
|||
|
{"mp3", 3, "audio/mpeg"},
|
|||
|
{"mp4", 3, "video/mp4"},
|
|||
|
{"mpe", 3, "video/mpeg"},
|
|||
|
{"3gp", 3, "video/mpeg"},
|
|||
|
{"msh", 3, "model/mesh"},
|
|||
|
{"mpg", 3, "video/mpeg"},
|
|||
|
{"dat", 3, "video/mpeg"},
|
|||
|
{"mpeg", 4, "video/mpeg"},
|
|||
|
{"mpga", 4, "audio/mpeg"},
|
|||
|
{"m2ts", 4, "video/mp2t"},
|
|||
|
{"movie", 5, "video/x-sgi-movie"},
|
|||
|
{"png", 3, "image/png"},
|
|||
|
{"bmp", 3, "image/bmp"},
|
|||
|
{"gif", 3, "image/gif"},
|
|||
|
{"jpe", 3, "image/jpeg"},
|
|||
|
{"jpg", 3, "image/jpeg"},
|
|||
|
{"jpeg", 4, "image/jpeg"},
|
|||
|
{"jfif", 4, "image/jpeg"},
|
|||
|
{"ra", 2, "audio/x-realaudio"},
|
|||
|
{"rmvb", 4, "appllication/vnd.rn-realmedia"},
|
|||
|
{"rm", 2, "appllication/vnd.rn-realmedia"},
|
|||
|
{"mp2", 3, "audio/mpeg"},
|
|||
|
{"mp3", 3, "audio/mpeg"},
|
|||
|
{"ram", 3, "audio/x-pn-realaudio"},
|
|||
|
{"wav", 3, "audio/x-wav"},
|
|||
|
{"wax", 3, "audio/x-ms-wax"},
|
|||
|
{"wma", 3, "audio/x-ms-wma"},
|
|||
|
{"wmv", 3, "video/x-ms-wmv"},
|
|||
|
{"mpga", 4, "audio/mpeg"},
|
|||
|
{"", 0, ""},
|
|||
|
};
|
|||
|
static int startFlag = 0;
|
|||
|
static pthread_t acceptThreadId;
|
|||
|
static httpdCallback gHttpdCallback = {NULL, NULL, NULL};
|
|||
|
|
|||
|
#define ISspace(x) isspace((int)(x))
|
|||
|
|
|||
|
#define SERVER_STRING "Server: jdbhttpd/0.1.0\r\n"
|
|||
|
|
|||
|
void *accept_request(void* client);
|
|||
|
void bad_request(int);
|
|||
|
void cat(int, FILE *);
|
|||
|
void cannot_execute(int);
|
|||
|
void error_die(const char *);
|
|||
|
void execute_cgi(int, const char *, const char *, const char *);
|
|||
|
int get_line(int, char *, int);
|
|||
|
void headers(int, const char *);
|
|||
|
void not_found(int);
|
|||
|
void serve_file(int, const char *);
|
|||
|
int startup(u_short *);
|
|||
|
void unimplemented(int);
|
|||
|
void requested_range_not_satisfiable(int sockfd);
|
|||
|
void serve_whole_file(int sockfd, const char *filename, FILE *resource);
|
|||
|
void serve_partial_file(int sockfd, const char *filename, FILE *resource, long long startPos, long long endPos, long long fileSize);
|
|||
|
void partial_headers(int sockfd, const char *filename, long long startPos, long long endPos);
|
|||
|
void partial_cat(int sockfd, FILE *resource, long long startPos, long long endPos, long long fileSize);
|
|||
|
ssize_t recv_wrap(int __fd, void *__buf, size_t __n, int __flags);
|
|||
|
ssize_t send_wrap(int __fd, __const void *__buf, size_t __n, int __flags);
|
|||
|
|
|||
|
|
|||
|
ssize_t recv_wrap(int __fd, void *__buf, size_t __n, int __flags)
|
|||
|
{
|
|||
|
int ret = 0;
|
|||
|
|
|||
|
fd_set rfd;
|
|||
|
FD_ZERO(&rfd);
|
|||
|
FD_SET(__fd, &rfd);
|
|||
|
struct timeval to = {1, 0};
|
|||
|
int result = select(__fd+1, &rfd, NULL, NULL, &to);
|
|||
|
if (result > 0)
|
|||
|
{
|
|||
|
ret = recv(__fd, __buf, __n, __flags);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
LOGD("error!, recv time out:1 sec pass\n");
|
|||
|
ret = -1;
|
|||
|
}
|
|||
|
|
|||
|
return ret;
|
|||
|
}
|
|||
|
ssize_t send_wrap(int __fd, __const void *__buf, size_t __n, int __flags)
|
|||
|
{
|
|||
|
int ret = 0;
|
|||
|
|
|||
|
fd_set wfd;
|
|||
|
FD_ZERO(&wfd);
|
|||
|
FD_SET(__fd, &wfd);
|
|||
|
struct timeval to = {1, 0};
|
|||
|
int result = 1;
|
|||
|
result = select(__fd+1, NULL, &wfd, NULL, &to);
|
|||
|
if(result > 0)
|
|||
|
{
|
|||
|
ret = send(__fd, __buf, __n, __flags);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
LOGD("error!, send time out:1 sec pass\n");
|
|||
|
ret = -1;
|
|||
|
}
|
|||
|
|
|||
|
return ret;
|
|||
|
}
|
|||
|
|
|||
|
/**********************************************************************/
|
|||
|
/* A request has caused a call to accept() on the server port to
|
|||
|
* return. Process the request appropriately.
|
|||
|
* Parameters: the socket connected to the client */
|
|||
|
/**********************************************************************/
|
|||
|
void *accept_request(void* client)
|
|||
|
{
|
|||
|
int client_sock = *(int*)client;
|
|||
|
delete (int*)client;
|
|||
|
char buf[1024];
|
|||
|
int numchars;
|
|||
|
char method[255];
|
|||
|
char url[255];
|
|||
|
char path[512];
|
|||
|
size_t i, j;
|
|||
|
struct stat st;
|
|||
|
int cgi = 0; /* becomes true if server decides this is a CGI
|
|||
|
* program */
|
|||
|
char *query_string = NULL;
|
|||
|
|
|||
|
int snd_size;
|
|||
|
socklen_t optlen;
|
|||
|
int ret;
|
|||
|
|
|||
|
optlen = sizeof(snd_size);
|
|||
|
ret = getsockopt(client_sock, SOL_SOCKET, SO_SNDBUF, (char*)&snd_size, &optlen);
|
|||
|
if(ret < 0)
|
|||
|
{
|
|||
|
LOGD("getsockopt failed\n");
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
LOGD("\ndefault snd buf:%d %d\n", snd_size, optlen);
|
|||
|
|
|||
|
// snd_size = 64*1024;
|
|||
|
snd_size /= 2;
|
|||
|
ret = setsockopt(client_sock, SOL_SOCKET, SO_SNDBUF, (const char*)&snd_size, optlen);
|
|||
|
|
|||
|
if(ret < 0)
|
|||
|
{
|
|||
|
LOGD("setsockopt failed\n");
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
ret = getsockopt(client_sock, SOL_SOCKET, SO_SNDBUF, (char*)&snd_size, &optlen);
|
|||
|
if(ret < 0)
|
|||
|
{
|
|||
|
LOGD("getsockopt failed tt\n");
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
LOGD("set snd buf:%d %d\n", snd_size, optlen);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
numchars = get_line(client_sock, buf, sizeof(buf));
|
|||
|
i = 0; j = 0;
|
|||
|
|
|||
|
LOGD("accept_request, get_line:%s", buf);
|
|||
|
while (!ISspace(buf[j]) && (i < sizeof(method) - 1))
|
|||
|
{
|
|||
|
method[i] = buf[j];
|
|||
|
i++; j++;
|
|||
|
}
|
|||
|
method[i] = '\0';
|
|||
|
LOGD("accept_request, method:%s", method);
|
|||
|
if (strcasecmp(method, "GET") && strcasecmp(method, "POST"))
|
|||
|
{
|
|||
|
LOGD("unimplemented");
|
|||
|
unimplemented(client_sock);
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
|
|||
|
if (strcasecmp(method, "POST") == 0)
|
|||
|
cgi = 1;
|
|||
|
|
|||
|
i = 0;
|
|||
|
while (ISspace(buf[j]) && (j < sizeof(buf)))
|
|||
|
j++;
|
|||
|
while (!ISspace(buf[j]) && (i < sizeof(url) - 1) && (j < sizeof(buf)))
|
|||
|
{
|
|||
|
url[i] = buf[j];
|
|||
|
i++; j++;
|
|||
|
}
|
|||
|
url[i] = '\0';
|
|||
|
|
|||
|
if (strcasecmp(method, "GET") == 0)
|
|||
|
{
|
|||
|
query_string = url;
|
|||
|
while ((*query_string != '?') && (*query_string != '\0'))
|
|||
|
query_string++;
|
|||
|
if (*query_string == '?')
|
|||
|
{
|
|||
|
cgi = 1;
|
|||
|
*query_string = '\0';
|
|||
|
query_string++;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
sprintf(path, "%s", url);
|
|||
|
if (path[strlen(path) - 1] == '/')
|
|||
|
strcat(path, "index.html");
|
|||
|
if (stat(path, &st) == -1 && strcmp(method, "POST") != 0) {
|
|||
|
while ((numchars > 0) && strcmp("\n", buf)) /* read & discard headers */
|
|||
|
numchars = get_line(client_sock, buf, sizeof(buf));
|
|||
|
not_found(client_sock);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if (!cgi) {
|
|||
|
LOGD("exe serve_file, path:%s", path);
|
|||
|
serve_file(client_sock, path);
|
|||
|
}
|
|||
|
else {
|
|||
|
LOGD("exe execute_cgi, path:%s, method:%s, query_string:%s", path, method, query_string);
|
|||
|
execute_cgi(client_sock, path, method, query_string);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
close(client_sock);
|
|||
|
return NULL;
|
|||
|
}
|
|||
|
|
|||
|
/**********************************************************************/
|
|||
|
/* Inform the client that a request it has made has a problem.
|
|||
|
* Parameters: client socket */
|
|||
|
/**********************************************************************/
|
|||
|
void bad_request(int client)
|
|||
|
{
|
|||
|
char buf[1024];
|
|||
|
|
|||
|
sprintf(buf, "HTTP/1.0 400 BAD REQUEST\r\n");
|
|||
|
send_wrap(client, buf, sizeof(buf), 0);
|
|||
|
sprintf(buf, "Content-type: text/html\r\n");
|
|||
|
send_wrap(client, buf, sizeof(buf), 0);
|
|||
|
sprintf(buf, "\r\n");
|
|||
|
send_wrap(client, buf, sizeof(buf), 0);
|
|||
|
sprintf(buf, "<P>Your browser sent a bad request, ");
|
|||
|
send_wrap(client, buf, sizeof(buf), 0);
|
|||
|
sprintf(buf, "such as a POST without a Content-Length.\r\n");
|
|||
|
send_wrap(client, buf, sizeof(buf), 0);
|
|||
|
}
|
|||
|
|
|||
|
/**********************************************************************/
|
|||
|
/* Put the entire contents of a file out on a socket. This function
|
|||
|
* is named after the UNIX "cat" command, because it might have been
|
|||
|
* easier just to do something like pipe, fork, and exec("cat").
|
|||
|
* Parameters: the client socket descriptor
|
|||
|
* FILE pointer for the file to cat */
|
|||
|
/**********************************************************************/
|
|||
|
void cat(int client, FILE *resource)
|
|||
|
{
|
|||
|
#if 1
|
|||
|
char buf[1024];
|
|||
|
int readlen;
|
|||
|
int sendret;
|
|||
|
|
|||
|
while((readlen = fread(buf, sizeof(char), 1024, resource)))
|
|||
|
{
|
|||
|
//printf("i = %d, readlen = %d\n", ++i, readlen);
|
|||
|
sendret = send_wrap(client, buf, readlen, 0);
|
|||
|
if(sendret < 0)
|
|||
|
{
|
|||
|
LOGD("[cat] send error! [%s]", strerror(errno));
|
|||
|
return;
|
|||
|
}
|
|||
|
}
|
|||
|
/* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݻ<EFBFBD><DDBB>ߴ<EFBFBD><DFB4><EFBFBD> */
|
|||
|
if(!feof(resource))
|
|||
|
{
|
|||
|
LOGD("[cat] end before eof");
|
|||
|
return;
|
|||
|
}
|
|||
|
#else
|
|||
|
char buf[1024];
|
|||
|
time_t startTime, curTime;
|
|||
|
time(&startTime);
|
|||
|
while (!feof(resource))
|
|||
|
{
|
|||
|
int sendlen = fread(buf, 1, sizeof(buf), resource);
|
|||
|
if (sendlen < 0) {
|
|||
|
LOGD("read error");
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
int ret = 0;
|
|||
|
while (ret < sendlen) {
|
|||
|
time(&curTime);
|
|||
|
if (curTime - startTime > 3) {
|
|||
|
LOGD("send nothing in 3 seconds, exit thread");
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
int sndret = send(client, buf+ret, sendlen-ret, 0);
|
|||
|
if (sndret < 0) {
|
|||
|
LOGD("send error:[%s]", strerror(errno));
|
|||
|
signal(SIGPIPE, SIG_IGN);
|
|||
|
usleep(100*1000);
|
|||
|
continue;
|
|||
|
}
|
|||
|
time(&startTime);
|
|||
|
ret += sndret;
|
|||
|
}
|
|||
|
}
|
|||
|
#endif
|
|||
|
LOGD("send file finish");
|
|||
|
}
|
|||
|
|
|||
|
/**********************************************************************/
|
|||
|
/* Inform the client that a CGI script could not be executed.
|
|||
|
* Parameter: the client socket descriptor. */
|
|||
|
/**********************************************************************/
|
|||
|
void cannot_execute(int client)
|
|||
|
{
|
|||
|
char buf[1024];
|
|||
|
|
|||
|
sprintf(buf, "HTTP/1.0 500 Internal Server Error\r\n");
|
|||
|
send_wrap(client, buf, strlen(buf), 0);
|
|||
|
sprintf(buf, "Content-type: text/html\r\n");
|
|||
|
send_wrap(client, buf, strlen(buf), 0);
|
|||
|
sprintf(buf, "\r\n");
|
|||
|
send_wrap(client, buf, strlen(buf), 0);
|
|||
|
sprintf(buf, "<P>Error prohibited CGI execution.\r\n");
|
|||
|
send_wrap(client, buf, strlen(buf), 0);
|
|||
|
}
|
|||
|
|
|||
|
/**********************************************************************/
|
|||
|
/* Print out an error message with perror() (for system errors; based
|
|||
|
* on value of errno, which indicates system call errors) and exit the
|
|||
|
* program indicating an error. */
|
|||
|
/**********************************************************************/
|
|||
|
void error_die(const char *sc)
|
|||
|
{
|
|||
|
perror(sc);
|
|||
|
exit(1);
|
|||
|
}
|
|||
|
|
|||
|
/**********************************************************************/
|
|||
|
/* Execute a CGI script. Will need to set environment variables as
|
|||
|
* appropriate.
|
|||
|
* Parameters: client socket descriptor
|
|||
|
* path to the CGI script */
|
|||
|
/**********************************************************************/
|
|||
|
void execute_cgi(int client, const char *path,
|
|||
|
const char *method, const char *query_string)
|
|||
|
{
|
|||
|
char buf[1024];
|
|||
|
int cgi_output[2];
|
|||
|
int cgi_input[2];
|
|||
|
pid_t pid;
|
|||
|
int status;
|
|||
|
int i;
|
|||
|
char c;
|
|||
|
int numchars = 1;
|
|||
|
int content_length = -1;
|
|||
|
|
|||
|
buf[0] = 'A'; buf[1] = '\0';
|
|||
|
if (strcasecmp(method, "GET") == 0)
|
|||
|
while ((numchars > 0) && strcmp("\n", buf)) /* read & discard headers */
|
|||
|
numchars = get_line(client, buf, sizeof(buf));
|
|||
|
else /* POST */
|
|||
|
{
|
|||
|
numchars = get_line(client, buf, sizeof(buf));
|
|||
|
LOGD("buf:%s", buf);
|
|||
|
while ((numchars > 0) && strcmp("\n", buf))
|
|||
|
{
|
|||
|
LOGD("buf:%s", buf);
|
|||
|
buf[15] = '\0';
|
|||
|
if (strcasecmp(buf, "Content-Length:") == 0)
|
|||
|
content_length = atoi(&(buf[16]));
|
|||
|
numchars = get_line(client, buf, sizeof(buf));
|
|||
|
}
|
|||
|
if (content_length == -1) {
|
|||
|
bad_request(client);
|
|||
|
return;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
sprintf(buf, "HTTP/1.0 200 OK\r\n");
|
|||
|
send_wrap(client, buf, strlen(buf), 0);
|
|||
|
const char *filename = strrchr(path, '/');
|
|||
|
if (filename != NULL) {
|
|||
|
filename++;
|
|||
|
} else {
|
|||
|
filename = (char*)path;
|
|||
|
}
|
|||
|
if (gHttpdCallback.httpdStatCallback != NULL) {
|
|||
|
gHttpdCallback.httpdStatCallback(POST_FILE_START, (void*)filename, strlen(filename)+1, gHttpdCallback.handler);
|
|||
|
}
|
|||
|
int recvLen = 0;
|
|||
|
time_t recvTime;
|
|||
|
time(&recvTime);
|
|||
|
while (recvLen < content_length) {
|
|||
|
time_t recvTimeout;
|
|||
|
time(&recvTimeout);
|
|||
|
if (recvTimeout - recvTime > 1) {
|
|||
|
if (gHttpdCallback.httpdStatCallback != NULL) {
|
|||
|
gHttpdCallback.httpdStatCallback(POST_FILE_ERROR, (void*)filename, strlen(filename)+1, gHttpdCallback.handler);
|
|||
|
}
|
|||
|
return ;
|
|||
|
}
|
|||
|
fd_set rfd;
|
|||
|
FD_ZERO(&rfd);
|
|||
|
FD_SET(client, &rfd);
|
|||
|
struct timeval tv = {0, 100000};
|
|||
|
int sResult = select(client + 1, &rfd, NULL, NULL, &tv);
|
|||
|
if (sResult > 0) {
|
|||
|
if (FD_ISSET(client, &rfd) != 0) {
|
|||
|
int recvRet = recv_wrap(client, buf, 1024, 0);
|
|||
|
if (recvRet < 0) {
|
|||
|
LOGD("recv error, errno [%d]", errno);
|
|||
|
if (gHttpdCallback.httpdStatCallback != NULL) {
|
|||
|
gHttpdCallback.httpdStatCallback(POST_FILE_ERROR, (void*)filename,
|
|||
|
strlen(filename)+1, gHttpdCallback.handler);
|
|||
|
}
|
|||
|
return ;
|
|||
|
}
|
|||
|
// LOGD("recv success, recvRet [%d], buf[%s]", recvRet, buf);
|
|||
|
if (gHttpdCallback.httpdDataCallback != NULL) {
|
|||
|
gHttpdCallback.httpdDataCallback((void*)buf, recvRet, gHttpdCallback.handler);
|
|||
|
}
|
|||
|
recvLen += recvRet;
|
|||
|
time(&recvTime);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
if (gHttpdCallback.httpdStatCallback != NULL) {
|
|||
|
gHttpdCallback.httpdStatCallback(POST_FILE_END, (void*)filename, strlen(filename)+1, gHttpdCallback.handler);
|
|||
|
}
|
|||
|
#if 0
|
|||
|
if (pipe(cgi_output) < 0) {
|
|||
|
cannot_execute(client);
|
|||
|
return;
|
|||
|
}
|
|||
|
if (pipe(cgi_input) < 0) {
|
|||
|
cannot_execute(client);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
if ( (pid = fork()) < 0 ) {
|
|||
|
cannot_execute(client);
|
|||
|
return;
|
|||
|
}
|
|||
|
if (pid == 0) /* child: CGI script */
|
|||
|
{
|
|||
|
char meth_env[255];
|
|||
|
char query_env[255];
|
|||
|
char length_env[255];
|
|||
|
|
|||
|
dup2(cgi_output[1], 1);
|
|||
|
dup2(cgi_input[0], 0);
|
|||
|
close(cgi_output[0]);
|
|||
|
close(cgi_input[1]);
|
|||
|
sprintf(meth_env, "REQUEST_METHOD=%s", method);
|
|||
|
putenv(meth_env);
|
|||
|
if (strcasecmp(method, "GET") == 0) {
|
|||
|
sprintf(query_env, "QUERY_STRING=%s", query_string);
|
|||
|
putenv(query_env);
|
|||
|
}
|
|||
|
else { /* POST */
|
|||
|
sprintf(length_env, "CONTENT_LENGTH=%d", content_length);
|
|||
|
putenv(length_env);
|
|||
|
}
|
|||
|
execl(path, path, NULL);
|
|||
|
exit(0);
|
|||
|
} else { /* parent */
|
|||
|
close(cgi_output[1]);
|
|||
|
close(cgi_input[0]);
|
|||
|
if (strcasecmp(method, "POST") == 0)
|
|||
|
for (i = 0; i < content_length; i++) {
|
|||
|
recv_wrap(client, &c, 1, 0);
|
|||
|
write(cgi_input[1], &c, 1);
|
|||
|
}
|
|||
|
while (read(cgi_output[0], &c, 1) > 0)
|
|||
|
send(client, &c, 1, 0);
|
|||
|
|
|||
|
close(cgi_output[0]);
|
|||
|
close(cgi_input[1]);
|
|||
|
waitpid(pid, &status, 0);
|
|||
|
}
|
|||
|
#endif
|
|||
|
}
|
|||
|
|
|||
|
/**********************************************************************/
|
|||
|
/* Get a line from a socket, whether the line ends in a newline,
|
|||
|
* carriage return, or a CRLF combination. Terminates the string read
|
|||
|
* with a null character. If no newline indicator is found before the
|
|||
|
* end of the buffer, the string is terminated with a null. If any of
|
|||
|
* the above three line terminators is read, the last character of the
|
|||
|
* string will be a linefeed and the string will be terminated with a
|
|||
|
* null character.
|
|||
|
* Parameters: the socket descriptor
|
|||
|
* the buffer to save the data in
|
|||
|
* the size of the buffer
|
|||
|
* Returns: the number of bytes stored (excluding null) */
|
|||
|
/**********************************************************************/
|
|||
|
int get_line(int sock, char *buf, int size)
|
|||
|
{
|
|||
|
int i = 0;
|
|||
|
char c = '\0';
|
|||
|
int n;
|
|||
|
|
|||
|
while ((i < size - 1) && (c != '\n'))
|
|||
|
{
|
|||
|
n = recv_wrap(sock, &c, 1, 0);
|
|||
|
/* DEBUG printf("%02X\n", c); */
|
|||
|
if (n > 0)
|
|||
|
{
|
|||
|
if (c == '\r')
|
|||
|
{
|
|||
|
n = recv_wrap(sock, &c, 1, MSG_PEEK);
|
|||
|
/* DEBUG printf("%02X\n", c); */
|
|||
|
if ((n > 0) && (c == '\n'))
|
|||
|
recv_wrap(sock, &c, 1, 0);
|
|||
|
else
|
|||
|
c = '\n';
|
|||
|
}
|
|||
|
buf[i] = c;
|
|||
|
i++;
|
|||
|
}
|
|||
|
else
|
|||
|
c = '\n';
|
|||
|
}
|
|||
|
buf[i] = '\0';
|
|||
|
|
|||
|
return(i);
|
|||
|
}
|
|||
|
|
|||
|
/**********************************************************************/
|
|||
|
/* Return the informational HTTP headers about a file. */
|
|||
|
/* Parameters: the socket to print the headers on
|
|||
|
* the name of the file */
|
|||
|
/**********************************************************************/
|
|||
|
void headers(int client, const char *filename)
|
|||
|
{
|
|||
|
#if 1
|
|||
|
char buf[1024];
|
|||
|
char contentType[128];
|
|||
|
char suffix[16];
|
|||
|
char *pos = NULL;
|
|||
|
int i;
|
|||
|
struct stat st;
|
|||
|
(void)filename; /* could use filename to determine file type */
|
|||
|
|
|||
|
|
|||
|
/* <20><><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD><C4BC><EFBFBD><EFBFBD><EFBFBD> */
|
|||
|
pos = (char*)strrchr(filename, '.');
|
|||
|
if(pos != NULL)
|
|||
|
{
|
|||
|
pos++;
|
|||
|
for(i = 0; mime_tab[i].ext_len != 0; i++)
|
|||
|
{
|
|||
|
if(strcmp(pos, mime_tab[i].ext) == 0)
|
|||
|
{
|
|||
|
strcpy(contentType, mime_tab[i].value);
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
if(mime_tab[i].ext_len == 0)
|
|||
|
{
|
|||
|
strcpy(contentType, "application/octet-stream");
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
strcpy(contentType, "application/octet-stream");
|
|||
|
}
|
|||
|
/* <20><>ȡ<EFBFBD>ļ<EFBFBD><C4BC><EFBFBD>Ϣ */
|
|||
|
stat(filename, &st);
|
|||
|
|
|||
|
LOGD("response[");
|
|||
|
strcpy(buf, "HTTP/1.1 200 OK\r\n");
|
|||
|
LOGD("%s", buf);
|
|||
|
send_wrap(client, buf, strlen(buf), 0);
|
|||
|
strcpy(buf, SERVER_STRING);
|
|||
|
LOGD("%s", buf);
|
|||
|
send_wrap(client, buf, strlen(buf), 0);
|
|||
|
//sprintf(buf, "Content-Type: text/html\r\n");
|
|||
|
sprintf(buf, "Content-Type: %s\r\n", contentType);
|
|||
|
LOGD("%s", buf);
|
|||
|
send_wrap(client, buf, strlen(buf), 0);
|
|||
|
sprintf(buf, "Content-Length: %lld\r\n", st.st_size);
|
|||
|
LOGD("%s", buf);
|
|||
|
send_wrap(client, buf, strlen(buf), 0);
|
|||
|
sprintf(buf, "Connection: Keep-alive\r\n");
|
|||
|
LOGD("%s", buf);
|
|||
|
send_wrap(client, buf, strlen(buf), 0);
|
|||
|
strcpy(buf, "\r\n");
|
|||
|
LOGD("%s", buf);
|
|||
|
send_wrap(client, buf, strlen(buf), 0);
|
|||
|
LOGD("]");
|
|||
|
|
|||
|
#else
|
|||
|
char buf[1024] = "";
|
|||
|
int i = 0;
|
|||
|
struct stat st;
|
|||
|
char *ext = strrchr(filename, '.')+sizeof('.');
|
|||
|
(void)filename; /* could use filename to determine file type */
|
|||
|
stat(filename, &st);
|
|||
|
for (i = 0; mime_tab[i].ext != NULL; i++)
|
|||
|
{
|
|||
|
if (strcmp(mime_tab[i].ext, ext) == 0)
|
|||
|
{
|
|||
|
snprintf(buf, 1024, "HTTP/1.1 206 Partial Content\r\nContent-Type: %s\r\nContent-Length: %lld\r\nContent-Ranges: bytes 0-%lld/%lld\r\nConnection: Keep-alive\r\n\r\n",
|
|||
|
mime_tab[0].value, st.st_size, st.st_size, st.st_size);
|
|||
|
LOGD("response[%s], mime_tab[%d].ext[%s]", buf, i, mime_tab[i].ext);
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
if (mime_tab[i].ext_len == NULL)
|
|||
|
{
|
|||
|
snprintf(buf, 1024, "HTTP/1.0 200 OK\r\n"SERVER_STRING"Content-Type: text/html\r\n\r\n");
|
|||
|
LOGD("response[%s]", buf);
|
|||
|
}
|
|||
|
send(client, buf, strlen(buf), 0);
|
|||
|
#endif
|
|||
|
}
|
|||
|
|
|||
|
/**********************************************************************/
|
|||
|
/* Give a client a 404 not found status message. */
|
|||
|
/**********************************************************************/
|
|||
|
void not_found(int client)
|
|||
|
{
|
|||
|
char buf[1024];
|
|||
|
|
|||
|
sprintf(buf, "HTTP/1.0 404 NOT FOUND\r\n");
|
|||
|
send_wrap(client, buf, strlen(buf), 0);
|
|||
|
sprintf(buf, SERVER_STRING);
|
|||
|
send_wrap(client, buf, strlen(buf), 0);
|
|||
|
sprintf(buf, "Content-Type: text/html\r\n");
|
|||
|
send_wrap(client, buf, strlen(buf), 0);
|
|||
|
sprintf(buf, "\r\n");
|
|||
|
send_wrap(client, buf, strlen(buf), 0);
|
|||
|
sprintf(buf, "<HTML><TITLE>Not Found</TITLE>\r\n");
|
|||
|
send_wrap(client, buf, strlen(buf), 0);
|
|||
|
sprintf(buf, "<BODY><P>The server could not fulfill\r\n");
|
|||
|
send_wrap(client, buf, strlen(buf), 0);
|
|||
|
sprintf(buf, "your request because the resource specified\r\n");
|
|||
|
send_wrap(client, buf, strlen(buf), 0);
|
|||
|
sprintf(buf, "is unavailable or nonexistent.\r\n");
|
|||
|
send_wrap(client, buf, strlen(buf), 0);
|
|||
|
sprintf(buf, "</BODY></HTML>\r\n");
|
|||
|
send_wrap(client, buf, strlen(buf), 0);
|
|||
|
}
|
|||
|
|
|||
|
/**********************************************************************/
|
|||
|
/* Send a regular file to the client. Use headers, and report
|
|||
|
* errors to client if they occur.
|
|||
|
* Parameters: a pointer to a file structure produced from the socket
|
|||
|
* file descriptor
|
|||
|
* the name of the file to serve */
|
|||
|
/**********************************************************************/
|
|||
|
void serve_file(int client, const char *filename)
|
|||
|
{
|
|||
|
FILE *resource = NULL;
|
|||
|
int numchars = 1;
|
|||
|
char buf[1024];
|
|||
|
long long startPos = 0; /*Range<67><65><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD><C4BC><EFBFBD>ʼλ<CABC><CEBB>*/
|
|||
|
long long endPos = 0; /*Range<67><65><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD><C4BC><EFBFBD><EFBFBD><EFBFBD>λ<EFBFBD><CEBB>*/
|
|||
|
int hasRange = 0;
|
|||
|
struct stat st;
|
|||
|
|
|||
|
|
|||
|
/* <20><><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD><C4BC><EFBFBD>ʼ/<2F><><EFBFBD><EFBFBD>λ<EFBFBD><CEBB> */
|
|||
|
numchars = get_line(client, buf, sizeof(buf)); /* <20><>ȡ<EFBFBD><C8A1>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD> */
|
|||
|
while ((numchars > 0) && strcmp("\n", buf))
|
|||
|
{
|
|||
|
LOGD("%s\n", buf);
|
|||
|
if (strncasecmp(buf, "Range:", 6) == 0)
|
|||
|
{
|
|||
|
LOGD("%s\n", buf);
|
|||
|
hasRange = 1;
|
|||
|
char *strRange;
|
|||
|
strRange = strchr(&buf[7], '='); /* =1234-2345 */
|
|||
|
strRange++; /* 1234 */
|
|||
|
char *strNum;
|
|||
|
strNum = strchr(strRange, '-'); /* -2345 */
|
|||
|
*strNum = '\0';
|
|||
|
strNum++; /* 2345 */
|
|||
|
|
|||
|
if(*strNum == '\r' || *strNum == '\n')/*<2A><><EFBFBD><EFBFBD>=1234-<2D><><EFBFBD><EFBFBD><EFBFBD>*/
|
|||
|
{
|
|||
|
LOGD("deal with =1234-");
|
|||
|
stat(filename, &st);
|
|||
|
startPos = atoll(strRange);
|
|||
|
endPos = (long long)st.st_size - 1; /*st_size<7A><65><EFBFBD><EFBFBD><EFBFBD>д<EFBFBD><D0B4>ļ<EFBFBD><C4BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>*/
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
startPos = atoll(strRange);
|
|||
|
endPos = atoll(strNum);
|
|||
|
}
|
|||
|
LOGD("the startPos = %lld\n", startPos);
|
|||
|
LOGD("the endPos = %lld\n", endPos);
|
|||
|
}
|
|||
|
numchars = get_line(client, buf, sizeof(buf));
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
resource = fopen(filename, "r");
|
|||
|
if (resource == NULL)
|
|||
|
{
|
|||
|
LOGD("resource is NULL\n");
|
|||
|
not_found(client);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if(hasRange == 1)
|
|||
|
{
|
|||
|
LOGD("doing serve_partial_file\n");
|
|||
|
/* <20><>ȡ<EFBFBD>ļ<EFBFBD><C4BC><EFBFBD>Ϣ */
|
|||
|
stat(filename, &st);
|
|||
|
|
|||
|
/*<2A>ж<EFBFBD><D0B6><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Range<67>Ƿ<EFBFBD>Ϸ<EFBFBD>*/
|
|||
|
if(startPos < 0 || endPos >= st.st_size) /* 0-1233/1234<33><34><EFBFBD>ļ<EFBFBD><C4BC><EFBFBD>0<EFBFBD><30>ʼ<EFBFBD><CABC> */
|
|||
|
{
|
|||
|
LOGD("requested_range_not_satisfiable\n");
|
|||
|
requested_range_not_satisfiable(client);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
LOGD("serve_partial_file\n");
|
|||
|
serve_partial_file(client, filename, resource, startPos, endPos, st.st_size);
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
LOGD("serve_whole_file\n");
|
|||
|
serve_whole_file(client, filename, resource);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
#if 0
|
|||
|
buf[0] = 'A'; buf[1] = '\0';
|
|||
|
while ((numchars > 0) && strcmp("\n", buf)) /* read & discard headers */
|
|||
|
numchars = get_line(client, buf, sizeof(buf));
|
|||
|
|
|||
|
resource = fopen(filename, "rb");
|
|||
|
if (resource == NULL)
|
|||
|
not_found(client);
|
|||
|
else
|
|||
|
{
|
|||
|
headers(client, filename);
|
|||
|
cat(client, resource);
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
fclose(resource);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
void requested_range_not_satisfiable(int sockfd)
|
|||
|
{
|
|||
|
char buf[1024];
|
|||
|
|
|||
|
sprintf(buf, "HTTP/1.1 416 Requested Range Not Satisfiable\r\n");
|
|||
|
LOGD("%s", buf);
|
|||
|
send_wrap(sockfd, buf, strlen(buf), 0);
|
|||
|
|
|||
|
sprintf(buf, SERVER_STRING);
|
|||
|
LOGD("%s", buf);
|
|||
|
send_wrap(sockfd, buf, strlen(buf), 0);
|
|||
|
|
|||
|
sprintf(buf, "Content-Type: text/html\r\n");
|
|||
|
LOGD("%s", buf);
|
|||
|
send_wrap(sockfd, buf, strlen(buf), 0);
|
|||
|
|
|||
|
sprintf(buf, "\r\n");
|
|||
|
LOGD("%s", buf);
|
|||
|
send_wrap(sockfd, buf, strlen(buf), 0);
|
|||
|
|
|||
|
sprintf(buf, "<HTML><TITLE>Requested Range Not Satisfiable</TITLE>\r\n");
|
|||
|
LOGD("%s", buf);
|
|||
|
send_wrap(sockfd, buf, strlen(buf), 0);
|
|||
|
|
|||
|
sprintf(buf, "<BODY><P>The server could not fulfill\r\n");
|
|||
|
LOGD("%s", buf);
|
|||
|
send_wrap(sockfd, buf, strlen(buf), 0);
|
|||
|
|
|||
|
sprintf(buf, "your request because the range requested\r\n");
|
|||
|
LOGD("%s", buf);
|
|||
|
send_wrap(sockfd, buf, strlen(buf), 0);
|
|||
|
|
|||
|
sprintf(buf, "is not satisfiable.\r\n");
|
|||
|
LOGD("%s", buf);
|
|||
|
send_wrap(sockfd, buf, strlen(buf), 0);
|
|||
|
|
|||
|
sprintf(buf, "</BODY></HTML>\r\n");
|
|||
|
LOGD("%s", buf);
|
|||
|
send_wrap(sockfd, buf, strlen(buf), 0);
|
|||
|
}
|
|||
|
|
|||
|
/* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD> */
|
|||
|
void serve_whole_file(int sockfd, const char *filename, FILE *resource)
|
|||
|
{
|
|||
|
headers(sockfd, filename);
|
|||
|
cat(sockfd, resource);
|
|||
|
}
|
|||
|
|
|||
|
/* <20><><EFBFBD>ز<EFBFBD><D8B2><EFBFBD><EFBFBD>ļ<EFBFBD> */
|
|||
|
void serve_partial_file(int sockfd, const char *filename, FILE *resource, long long startPos, long long endPos, long long fileSize)
|
|||
|
{
|
|||
|
partial_headers(sockfd, filename, startPos, endPos);
|
|||
|
partial_cat(sockfd, resource, startPos, endPos, fileSize);
|
|||
|
}
|
|||
|
|
|||
|
/* <20><><EFBFBD>ز<EFBFBD><D8B2><EFBFBD><EFBFBD>ļ<EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD>Ӧͷ<D3A6><CDB7> */
|
|||
|
void partial_headers(int sockfd, const char *filename, long long startPos, long long endPos)
|
|||
|
{
|
|||
|
char buf[1024];
|
|||
|
char contentType[128];
|
|||
|
char suffix[16];
|
|||
|
char *pos = NULL;
|
|||
|
int i;
|
|||
|
//long long resstartPos = startPos;
|
|||
|
//long long resendPos = endPo
|
|||
|
struct stat st;
|
|||
|
(void)filename; /* could use filename to determine file type */
|
|||
|
|
|||
|
|
|||
|
/* <20><><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD><C4BC><EFBFBD><EFBFBD><EFBFBD> */
|
|||
|
pos = (char*)strrchr(filename, '.');
|
|||
|
if(pos != NULL)
|
|||
|
{
|
|||
|
pos++;
|
|||
|
for(i = 0; mime_tab[i].ext_len != 0; i++)
|
|||
|
{
|
|||
|
if(strcmp(pos, mime_tab[i].ext) == 0)
|
|||
|
{
|
|||
|
strcpy(contentType, mime_tab[i].value);
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
if(mime_tab[i].ext_len == 0)
|
|||
|
{
|
|||
|
strcpy(contentType, "application/octet-stream");
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
strcpy(contentType, "application/octet-stream");
|
|||
|
}
|
|||
|
|
|||
|
/* <20><>ȡ<EFBFBD>ļ<EFBFBD><C4BC><EFBFBD>Ϣ */
|
|||
|
stat(filename, &st);
|
|||
|
|
|||
|
strcpy(buf, "HTTP/1.1 206 Partial Content\r\n");
|
|||
|
LOGD("%s", buf);
|
|||
|
send_wrap(sockfd, buf, strlen(buf), 0);
|
|||
|
|
|||
|
strcpy(buf, SERVER_STRING);
|
|||
|
LOGD("%s", buf);
|
|||
|
send_wrap(sockfd, buf, strlen(buf), 0);
|
|||
|
|
|||
|
sprintf(buf, "Content-Type: %s\r\n", contentType);
|
|||
|
LOGD("%s", buf);
|
|||
|
send_wrap(sockfd, buf, strlen(buf), 0);
|
|||
|
|
|||
|
sprintf(buf, "Content-Length: %lld\r\n", endPos-startPos+1);//<2F>˴<EFBFBD><CBB4><EFBFBD>Ӧ<EFBFBD><D3A6>Ϊ<EFBFBD>ܴ<EFBFBD>Сst.st_size<7A><65><EFBFBD><EFBFBD>Ӧ<EFBFBD><D3A6>Ϊʵ<CEAA>ʷ<EFBFBD><CAB7>صij<D8B5><C4B3><EFBFBD>st.st_size);
|
|||
|
LOGD("%s", buf);
|
|||
|
printf("the st.st_size is %lld\n", st.st_size);
|
|||
|
send_wrap(sockfd, buf, strlen(buf), 0);
|
|||
|
|
|||
|
sprintf(buf, "Content-Range: bytes %lld-%lld/%lld\r\n", startPos, endPos, st.st_size);
|
|||
|
LOGD("%s", buf);
|
|||
|
send_wrap(sockfd, buf, strlen(buf), 0);
|
|||
|
|
|||
|
sprintf(buf, "Connection: Keep-Alive\r\n");
|
|||
|
LOGD("%s", buf);
|
|||
|
send_wrap(sockfd, buf, strlen(buf), 0);
|
|||
|
|
|||
|
strcpy(buf, "\r\n");
|
|||
|
send_wrap(sockfd, buf, strlen(buf), 0);
|
|||
|
}
|
|||
|
|
|||
|
/* <20><><EFBFBD>ز<EFBFBD><D8B2><EFBFBD><EFBFBD><EFBFBD>Ӧʱ<D3A6><CAB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> */
|
|||
|
void partial_cat(int sockfd, FILE *resource, long long startPos, long long endPos, long long fileSize)
|
|||
|
{
|
|||
|
char buf[4096];
|
|||
|
int i = 0;
|
|||
|
int readlen;
|
|||
|
int sendret;
|
|||
|
long long sendlength = endPos - startPos + 1; /* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݳ<EFBFBD><DDB3><EFBFBD> */
|
|||
|
|
|||
|
/*<2A>ļ<EFBFBD><C4BC><EFBFBD><EFBFBD><EFBFBD>2G<32><47>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD>м<EFBFBD><D0BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>*/
|
|||
|
if(startPos <= 2147483647)
|
|||
|
{ /*˳<><CBB3>λ*/
|
|||
|
if(fseek(resource, startPos, SEEK_SET) != 0)
|
|||
|
{
|
|||
|
LOGD("[partial_cat] fseek error!\n");
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
/*<2A><><EFBFBD><EFBFBD>λ*/
|
|||
|
long long rStartPos = (fileSize - 1) - startPos;
|
|||
|
if(fseek(resource, rStartPos, SEEK_END) != 0)
|
|||
|
{
|
|||
|
LOGD("[partial_cat] reverse fseek error!\n");
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
while((readlen = fread(buf, sizeof(char), 4096, resource)))
|
|||
|
{
|
|||
|
//printf("i = %d, readlen = %d\n", ++i, readlen);
|
|||
|
if(sendlength < readlen)
|
|||
|
{
|
|||
|
//LOGD("i = %d, sendlength = %d\n", ++i, sendlength);
|
|||
|
|
|||
|
sendret = send_wrap(sockfd, buf, sendlength, 0);
|
|||
|
if(sendret < 0)
|
|||
|
{
|
|||
|
LOGD("[partial_cat] send error! [%s]\n", strerror(errno));
|
|||
|
return;
|
|||
|
}
|
|||
|
sendlength -= sendlength;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
//LOGD("i = %d, readlen = %d\n", ++i, readlen);
|
|||
|
|
|||
|
sendret = send_wrap(sockfd, buf, readlen, 0);
|
|||
|
if(sendret < 0)
|
|||
|
{
|
|||
|
LOGD("[partial_cat] send error! [%s]\n", strerror(errno));
|
|||
|
return;
|
|||
|
}
|
|||
|
++i;
|
|||
|
|
|||
|
//if(i%500 == 0)
|
|||
|
//{
|
|||
|
// struct timeval t_timeval;
|
|||
|
// t_timeval.tv_sec = DOWNLOAD_SPEED_SEC;
|
|||
|
// t_timeval.tv_usec = DOWNLOAD_SPEED_MICRO_SEC;
|
|||
|
usleep(50000);
|
|||
|
//select(0, NULL, NULL, NULL, &t_timeval);
|
|||
|
//}
|
|||
|
|
|||
|
sendlength -= readlen;
|
|||
|
}
|
|||
|
if(sendlength == 0)
|
|||
|
{
|
|||
|
/* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> */
|
|||
|
//LOGD("sendlength == 0\n");
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
/* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݻ<EFBFBD><DDBB>ߴ<EFBFBD><DFB4><EFBFBD> */
|
|||
|
if(ferror(resource))
|
|||
|
{
|
|||
|
LOGD("[partial_cat] end before eof\n");
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
LOGD("send partial file finish");
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/**********************************************************************/
|
|||
|
/* This function starts the process of listening for web connections
|
|||
|
* on a specified port. If the port is 0, then dynamically allocate a
|
|||
|
* port and modify the original port variable to reflect the actual
|
|||
|
* port.
|
|||
|
* Parameters: pointer to variable containing the port to connect on
|
|||
|
* Returns: the socket */
|
|||
|
/**********************************************************************/
|
|||
|
int startup(u_short *port)
|
|||
|
{
|
|||
|
int httpd = 0;
|
|||
|
struct sockaddr_in name;
|
|||
|
|
|||
|
httpd = socket(PF_INET, SOCK_STREAM, 0);
|
|||
|
if (httpd == -1)
|
|||
|
error_die("socket");
|
|||
|
memset(&name, 0, sizeof(name));
|
|||
|
name.sin_family = AF_INET;
|
|||
|
name.sin_port = htons(*port);
|
|||
|
name.sin_addr.s_addr = htonl(INADDR_ANY);
|
|||
|
if (bind(httpd, (struct sockaddr *)&name, sizeof(name)) < 0)
|
|||
|
error_die("bind");
|
|||
|
if (*port == 0) /* if dynamically allocating a port */
|
|||
|
{
|
|||
|
int namelen = sizeof(name);
|
|||
|
if (getsockname(httpd, (struct sockaddr *)&name, (socklen_t*)&namelen) == -1)
|
|||
|
error_die("getsockname");
|
|||
|
*port = ntohs(name.sin_port);
|
|||
|
}
|
|||
|
if (listen(httpd, 10) < 0)
|
|||
|
error_die("listen");
|
|||
|
return(httpd);
|
|||
|
}
|
|||
|
|
|||
|
/**********************************************************************/
|
|||
|
/* Inform the client that the requested web method has not been
|
|||
|
* implemented.
|
|||
|
* Parameter: the client socket */
|
|||
|
/**********************************************************************/
|
|||
|
void unimplemented(int client)
|
|||
|
{
|
|||
|
char buf[1024];
|
|||
|
|
|||
|
sprintf(buf, "HTTP/1.0 501 Method Not Implemented\r\n");
|
|||
|
send_wrap(client, buf, strlen(buf), 0);
|
|||
|
sprintf(buf, SERVER_STRING);
|
|||
|
send_wrap(client, buf, strlen(buf), 0);
|
|||
|
sprintf(buf, "Content-Type: text/html\r\n");
|
|||
|
send_wrap(client, buf, strlen(buf), 0);
|
|||
|
sprintf(buf, "\r\n");
|
|||
|
send_wrap(client, buf, strlen(buf), 0);
|
|||
|
sprintf(buf, "<HTML><HEAD><TITLE>Method Not Implemented\r\n");
|
|||
|
send_wrap(client, buf, strlen(buf), 0);
|
|||
|
sprintf(buf, "</TITLE></HEAD>\r\n");
|
|||
|
send_wrap(client, buf, strlen(buf), 0);
|
|||
|
sprintf(buf, "<BODY><P>HTTP request method not supported.\r\n");
|
|||
|
send_wrap(client, buf, strlen(buf), 0);
|
|||
|
sprintf(buf, "</BODY></HTML>\r\n");
|
|||
|
send_wrap(client, buf, strlen(buf), 0);
|
|||
|
}
|
|||
|
|
|||
|
/**********************************************************************/
|
|||
|
void* acceptThread(void *argv)
|
|||
|
{
|
|||
|
int server_sock = -1;
|
|||
|
|
|||
|
#ifdef SDV
|
|||
|
u_short port = 80;
|
|||
|
#else
|
|||
|
u_short port = 8082;
|
|||
|
#endif
|
|||
|
int client_sock = -1;
|
|||
|
struct sockaddr_in client_name;
|
|||
|
int client_name_len = sizeof(client_name);
|
|||
|
pthread_t newthread;
|
|||
|
|
|||
|
server_sock = startup(&port);
|
|||
|
printf("httpd running on port %d\n", port);
|
|||
|
startFlag = 1;
|
|||
|
while(startFlag == 1)
|
|||
|
{
|
|||
|
fd_set rfd;
|
|||
|
FD_ZERO(&rfd);
|
|||
|
FD_SET(server_sock, &rfd);
|
|||
|
struct timeval to = {1, 0};
|
|||
|
int selectResult = select(server_sock+1, &rfd, NULL, NULL, &to);
|
|||
|
if (selectResult > 0)
|
|||
|
{
|
|||
|
client_sock = accept(server_sock, (struct sockaddr *)&client_name, (socklen_t*)&client_name_len);
|
|||
|
if (client_sock == -1)
|
|||
|
{
|
|||
|
perror("accept");
|
|||
|
continue;
|
|||
|
}
|
|||
|
LOGD("accept success, client_sock:%d", client_sock);
|
|||
|
/* accept_request(client_sock); */
|
|||
|
int *client_sock_ptr = new int;
|
|||
|
*client_sock_ptr = client_sock;
|
|||
|
// if (pthread_create(&newthread, NULL, accept_request, (void*)client_sock_ptr) != 0)
|
|||
|
// {
|
|||
|
// perror("pthread_create");
|
|||
|
// continue;
|
|||
|
// }
|
|||
|
// pthread_detach(newthread);
|
|||
|
accept_request(client_sock_ptr);
|
|||
|
}
|
|||
|
else if(selectResult < 0)
|
|||
|
{
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
startFlag = 0;
|
|||
|
close(server_sock);
|
|||
|
|
|||
|
return(0);
|
|||
|
}
|
|||
|
|
|||
|
int startHttpd(httpdCallback *callback)
|
|||
|
{
|
|||
|
/*<2A><><EFBFBD><EFBFBD>SIGPIPE<50>ź<EFBFBD>*/
|
|||
|
signal(SIGPIPE, SIG_IGN);
|
|||
|
printf("block SIGPIPE\n");
|
|||
|
if (startFlag == 1) {
|
|||
|
return -1;
|
|||
|
}
|
|||
|
|
|||
|
if(callback)
|
|||
|
{
|
|||
|
gHttpdCallback.httpdDataCallback = callback->httpdDataCallback;
|
|||
|
gHttpdCallback.httpdStatCallback = callback->httpdStatCallback;
|
|||
|
gHttpdCallback.handler = callback->handler;
|
|||
|
}
|
|||
|
if(pthread_create(&acceptThreadId, NULL, acceptThread, NULL) != 0) {
|
|||
|
perror("pthread_create");
|
|||
|
}
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
int stopHttpd()
|
|||
|
{
|
|||
|
startFlag = 0;
|
|||
|
pthread_join(acceptThreadId, NULL);
|
|||
|
gHttpdCallback.httpdDataCallback = NULL;
|
|||
|
gHttpdCallback.httpdStatCallback = NULL;
|
|||
|
gHttpdCallback.handler = NULL;
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|