📄 server.c
字号:
/* Copyright information is at end of file */#include <assert.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <time.h>#include <errno.h>#ifdef WIN32 #include <io.h>#else #include <unistd.h> #include <grp.h>#endif#include <fcntl.h>#include "xmlrpc_config.h"#include "mallocvar.h"#include "xmlrpc-c/string_int.h"#include "xmlrpc-c/sleep_int.h"#include "xmlrpc-c/abyss.h"#include "trace.h"#include "session.h"#include "conn.h"#include "socket.h"#ifdef WIN32 #include "socket_win.h"#else #include "socket_unix.h"#endif#include "http.h"#include "date.h"#include "abyss_info.h"#include "server.h"voidServerTerminate(TServer * const serverP) { struct _TServer * const srvP = serverP->srvP; srvP->terminationRequested = true;}voidServerResetTerminate(TServer * const serverP) { struct _TServer * const srvP = serverP->srvP; srvP->terminationRequested = false;}typedef int (*TQSortProc)(const void *, const void *);static intcmpfilenames(const TFileInfo **f1,const TFileInfo **f2) { if (((*f1)->attrib & A_SUBDIR) && !((*f2)->attrib & A_SUBDIR)) return (-1); if (!((*f1)->attrib & A_SUBDIR) && ((*f2)->attrib & A_SUBDIR)) return 1; return strcmp((*f1)->name,(*f2)->name);}static intcmpfiledates(const TFileInfo **f1,const TFileInfo **f2) { if (((*f1)->attrib & A_SUBDIR) && !((*f2)->attrib & A_SUBDIR)) return (-1); if (!((*f1)->attrib & A_SUBDIR) && ((*f2)->attrib & A_SUBDIR)) return 1; return ((*f1)->time_write-(*f2)->time_write);}static voiddetermineSortType(const char * const query, abyss_bool * const ascendingP, uint16_t * const sortP, abyss_bool * const textP, const char ** const errorP) { *ascendingP = TRUE; *sortP = 1; *textP = FALSE; *errorP = NULL; if (query) { if (xmlrpc_streq(query, "plain")) *textP = TRUE; else if (xmlrpc_streq(query, "name-up")) { *sortP = 1; *ascendingP = TRUE; } else if (xmlrpc_streq(query, "name-down")) { *sortP = 1; *ascendingP = FALSE; } else if (xmlrpc_streq(query, "date-up")) { *sortP = 2; *ascendingP = TRUE; } else if (xmlrpc_streq(query, "date-down")) { *sortP = 2; *ascendingP = FALSE; } else { xmlrpc_asprintf(errorP, "invalid query value '%s'", query); } }}static voidgenerateListing(TList * const listP, char * const z, const char * const uri, TPool * const poolP, const char ** const errorP, uint16_t * const responseStatusP) { TFileInfo fileinfo; TFileFind findhandle; *errorP = NULL; if (!FileFindFirst(&findhandle, z, &fileinfo)) { *responseStatusP = ResponseStatusFromErrno(errno); xmlrpc_asprintf(errorP, "Can't read first entry in directory"); } else { ListInit(listP); do { TFileInfo * fi; /* Files whose names start with a dot are ignored */ /* This includes implicitly the ./ and ../ */ if (*fileinfo.name == '.') { if (xmlrpc_streq(fileinfo.name, "..")) { if (xmlrpc_streq(uri, "/")) continue; } else continue; } fi = (TFileInfo *)PoolAlloc(poolP, sizeof(fileinfo)); if (fi) { abyss_bool success; memcpy(fi, &fileinfo, sizeof(fileinfo)); success = ListAdd(listP, fi); if (!success) xmlrpc_asprintf(errorP, "ListAdd() failed"); } else xmlrpc_asprintf(errorP, "PoolAlloc() failed."); } while (!*errorP && FileFindNext(&findhandle, &fileinfo)); if (*errorP) { *responseStatusP = 500; ListFree(listP); } FileFindClose(&findhandle); }}static voidsendDirectoryDocument(TList * const listP, abyss_bool const ascending, uint16_t const sort, abyss_bool const text, const char * const uri, MIMEType * const mimeTypeP, TSession * const sessionP, char * const z) { char *p,z1[26],z2[20],z3[9],u; const char * z4; int16_t i; uint32_t k; if (text) { sprintf(z, "Index of %s" CRLF, uri); i = strlen(z)-2; p = z + i + 2; while (i > 0) { *(p++) = '-'; --i; } *p = '\0'; strcat(z, CRLF CRLF "Name Size " "Date-Time Type" CRLF "------------------------------------" "--------------------------------------------"CRLF); } else { sprintf(z, "<HTML><HEAD><TITLE>Index of %s</TITLE></HEAD><BODY>" "<H1>Index of %s</H1><PRE>", uri, uri); strcat(z, "Name Size " "Date-Time Type<HR WIDTH=100%>"CRLF); } HTTPWriteBodyChunk(sessionP, z, strlen(z)); /* Sort the files */ qsort(listP->item, listP->size, sizeof(void *), (TQSortProc)(sort == 1 ? cmpfilenames : cmpfiledates)); /* Write the listing */ if (ascending) i = 0; else i = listP->size - 1; while ((i < listP->size) && (i >= 0)) { TFileInfo * fi; struct tm ftm; fi = listP->item[i]; if (ascending) ++i; else --i; strcpy(z, fi->name); k = strlen(z); if (fi->attrib & A_SUBDIR) { z[k++] = '/'; z[k] = '\0'; } if (k > 24) { z[10] = '\0'; strcpy(z1, z); strcat(z1, "..."); strcat(z1, z + k - 11); k = 24; p = z1 + 24; } else { strcpy(z1, z); ++k; p = z1 + k; while (k < 25) z1[k++] = ' '; z1[25] = '\0'; } ftm = *gmtime(&fi->time_write); sprintf(z2, "%02u/%02u/%04u %02u:%02u:%02u",ftm.tm_mday,ftm.tm_mon+1, ftm.tm_year+1900,ftm.tm_hour,ftm.tm_min,ftm.tm_sec); if (fi->attrib & A_SUBDIR) { strcpy(z3, " -- "); z4 = "Directory"; } else { if (fi->size < 9999) u = 'b'; else { fi->size /= 1024; if (fi->size < 9999) u = 'K'; else { fi->size /= 1024; if (fi->size < 9999) u = 'M'; else u = 'G'; } } sprintf(z3, "%5llu %c", fi->size, u); if (xmlrpc_streq(fi->name, "..")) z4 = ""; else z4 = MIMETypeFromFileName2(mimeTypeP, fi->name); if (!z4) z4 = "Unknown"; } if (text) sprintf(z, "%s%s %s %s %s"CRLF, z1, p, z3, z2, z4); else sprintf(z, "<A HREF=\"%s%s\">%s</A>%s %s %s %s"CRLF, fi->name, fi->attrib & A_SUBDIR ? "/" : "", z1, p, z3, z2, z4); HTTPWriteBodyChunk(sessionP, z, strlen(z)); } /* Write the tail of the file */ if (text) strcpy(z, SERVER_PLAIN_INFO); else strcpy(z, "</PRE>" SERVER_HTML_INFO "</BODY></HTML>" CRLF CRLF); HTTPWriteBodyChunk(sessionP, z, strlen(z));}static voidfileDate(TSession * const sessionP, time_t const statFilemodTime, TDate * const fileDateP) { abyss_bool haveDate; TDate filemodDate; haveDate = DateFromLocal(&filemodDate, statFilemodTime); if (haveDate) { if (DateCompare(&sessionP->date, &filemodDate) < 0) *fileDateP = sessionP->date; else *fileDateP = filemodDate; } else *fileDateP = sessionP->date;}static abyss_boolServerDirectoryHandler(TSession * const r, char * const z, time_t const fileModTime, MIMEType * const mimeTypeP) { TList list; abyss_bool text; abyss_bool ascending; uint16_t sort; /* 1=by name, 2=by date */ TPool pool; TDate date; const char * error; uint16_t responseStatus; TDate dirdate; const char * imsHdr; determineSortType(r->request_info.query, &ascending, &sort, &text, &error); if (error) { ResponseStatus(r,400); xmlrpc_strfree(error); return TRUE; } fileDate(r, fileModTime, &dirdate); imsHdr = RequestHeaderValue(r, "If-Modified-Since"); if (imsHdr) { if (DateDecode(imsHdr, &date)) { if (DateCompare(&dirdate, &date) <= 0) { ResponseStatus(r, 304); ResponseWrite(r); return TRUE; } } } if (!PoolCreate(&pool, 1024)) { ResponseStatus(r, 500); return TRUE; } generateListing(&list, z, r->request_info.uri, &pool, &error, &responseStatus); if (error) { ResponseStatus(r, responseStatus); xmlrpc_strfree(error); PoolFree(&pool); return TRUE; } /* Send something to the user to show that we are still alive */ ResponseStatus(r, 200); ResponseContentType(r, (text ? "text/plain" : "text/html")); if (DateToString(&dirdate, z)) ResponseAddField(r, "Last-Modified", z); ResponseChunked(r); ResponseWrite(r); if (r->request_info.method!=m_head) sendDirectoryDocument(&list, ascending, sort, text, r->request_info.uri, mimeTypeP, r, z); HTTPWriteEndChunk(r); /* Free memory and exit */ ListFree(&list); PoolFree(&pool); return TRUE;}#define BOUNDARY "##123456789###BOUNDARY"static voidsendBody(TSession * const sessionP, TFile * const fileP, uint64_t const filesize, const char * const mediatype, uint64_t const start0, uint64_t const end0, char * const z) { if (sessionP->ranges.size == 0) ConnWriteFromFile(sessionP->conn, fileP, 0, filesize - 1, z, 4096, 0); else if (sessionP->ranges.size == 1) ConnWriteFromFile(sessionP->conn, fileP, start0, end0, z, 4096, 0); else { uint64_t i; for (i = 0; i <= sessionP->ranges.size; ++i) { ConnWrite(sessionP->conn,"--", 2); ConnWrite(sessionP->conn, BOUNDARY, strlen(BOUNDARY)); ConnWrite(sessionP->conn, CRLF, 2); if (i < sessionP->ranges.size) { uint64_t start; uint64_t end; abyss_bool decoded; decoded = RangeDecode((char *)(sessionP->ranges.item[i]), filesize, &start, &end); if (decoded) { /* Entity header, not response header */ sprintf(z, "Content-type: %s" CRLF "Content-range: bytes %llu-%llu/%llu" CRLF "Content-length: %llu" CRLF CRLF, mediatype, start, end, filesize, end-start+1); ConnWrite(sessionP->conn, z, strlen(z));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -