问题:浏览器与文件服务器如何交互?
浏览器与文件服务器的交互
文件浏览
- 点击列表中的文件夹 → 进入子文件夹(展现子文件夹列表)
文件下载
- 点击列表中的文件 → 下载指标文件
错误处理
- 向服务器发送谬误申请 → 浏览不存在的文件夹 / 下载不存在的文件
文件浏览交互实现
实现中的要害概念
共享文件夹(root)
- 服务端启动时指定的共享文件夹门路(服务零碎中的门路)
申请门路(req)
- 文件 / 文件夹 在服务端上绝对共享文件夹的门路
绝对路径
AbsPath = root + "/" + req
根底函数定义
char *GetAbsPath(const char *relative, const char *root)
- 拼接 root 和 relative, 返回绝对路径,返回值需开释 (free)
int isDotPath(const char *path)
- 判断 path 是否为非凡门路 "." 或 ".."
int GetEntryCount(const char *path)
- 返回 path 门路下的 (文件 + 文件夹)总数
编程试验:根底函数实现
static char *GetAbsPath(const char *relative, const char *root){ int reLen = strlen(relative); int rootLen = strlen(root); char *ret = malloc(reLen + rootLen + 2); if (ret) { strcpy(ret, root); if ((relative[0] == '/') && (ret[rootLen-1] == '/')) ret[rootLen - 1] = 0; if ((relative[0] != '/') && (ret[rootLen-1] != '/')) strcat(ret, "/"); strcat(ret, relative); } return ret;}static int IsDotPath(const char *path){ int ret = -1; if (path) { ret = (strcmp(path, ".") == 0) || (strcmp(path, "..") == 0); } return ret;}static int GetEntryCount(const char *path){ int ret = -1; DIR *dirp = opendir(path); if (dirp != NULL) { struct dirent *dp = NULL; ret = 0; while ((dp = readdir(dirp)) != NULL) { if (!IsDotPath(dp->d_name)) { ret ++; } } } closedir(dirp); return ret;}
要害数据结构定义
enum { TypeAll = 0x00, TypeDir = 0x04, TypeFile = 0x08};typdef struct { const int length; RowInfo data[];}FileEntry;typedef struct { char link[2048]; char name[255]; char type[32]; char size[32]; char time[32];}RowInfo;
要害函数定义
int MakeEntryItem(RowInfo *item, struct dirent *dp, const char *ap, const char *req);
- 依据 dp 所指向的 文件 或 文件夹 生成 RowInfo 数据结构,胜利返回 true, 失败返回 false
FileEntry *GetEntry(const char *req, const char *root, int type);
- 获取 root/req 门路下 文件 和 文件夹 所对应的 RowInfo 数组,返回值需开释 (free)
char *MakeHTML(const char *req, const char *root);
- 创立 root/req 门路下 文件 和 文件夹 所形成的 HTML 页面,返回值需开释 (free)
服务端实现设计
非凡页面设计
编程试验:文件浏览交互实现
#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <dirent.h>#include <unistd.h>#include <time.h>#include "page.h"#include "response.h"enum { TypeAll = 0x00, TypeDir = 0x04, TypeFile = 0x08 };typedef struct { const int length; RowInfo data[];} FileEntry;static char* GetAbsPath(const char* relative, const char* root){ int reLen = strlen(relative); int rootLen = strlen(root); char* ret = malloc(reLen + rootLen + 2); if( ret ) { strcpy(ret, root); if( (relative[0] == '/') && (ret[rootLen-1] == '/') ) ret[rootLen-1] = 0; if( (relative[0] != '/') && (ret[rootLen-1] != '/') ) strcat(ret, "/"); strcat(ret, relative); } return ret;}static int IsDotPath(const char* path){ int ret = -1; if( path ) { ret = (strcmp(path, ".") == 0) || (strcmp(path, "..") == 0); } return ret;}static int GetEntryCount(const char* path){ int ret = -1; DIR* dirp = opendir(path); if( dirp != NULL ) { struct dirent* dp = NULL; ret = 0; while( (dp = readdir(dirp)) != NULL ) { if( !IsDotPath(dp->d_name) ) { ret++; } } } closedir(dirp); return ret;}static void SortFileEntry(FileEntry* fe){ RowInfo* temp = malloc(sizeof(*temp)); if( fe && temp ) { int i = 0; int j = 0; for(i=0; i<fe->length; i++) { int min = i; for(j=i; j<fe->length; j++) { if( strcmp(fe->data[min].name, fe->data[j].name) > 0 ) { min = j; } } *temp = fe->data[i]; fe->data[i] = fe->data[min]; fe->data[min] = *temp; } } free(temp);}static int MakeEntryItem(RowInfo* item, struct dirent* dp, const char* ap, const char* req){ int ret = 0; char buf[32] = {0}; struct stat sb = {0}; char* path = GetAbsPath(dp->d_name, ap); if( path && (ret = (stat(path, &sb)) != -1) ) { strcpy(item->link, req); (strcmp(req, "/") != 0) ? strcat(item->link, "/") : 0; strcat(item->link, dp->d_name); strcpy(item->name, dp->d_name); if( dp->d_type == TypeFile ) { strcpy(item->type, "File"); if( sb.st_size < 1024 ) { sprintf(buf, "%ld", sb.st_size); strcpy(item->size, buf); strcat(item->size, " Byte"); } else if( (sb.st_size / 1024) < 1024 ) { sprintf(buf, "%ld", sb.st_size/1024); strcpy(item->size, buf); strcat(item->size, " KB"); } else { sprintf(buf, "%ld", sb.st_size/1024/1024); strcpy(item->size, buf); strcat(item->size, " MB"); } } else { strcpy(item->type, "Folder"); sprintf(buf, "%d", GetEntryCount(path)); strcpy(item->size, buf); strcat(item->size, " Item"); } strcpy(item->time, ctime(&sb.st_mtime)); } free(path); return ret;}static FileEntry* GetEntry(const char* req, const char* root, int type){ char* ap = GetAbsPath(req, root); DIR* dirp = NULL; FileEntry* ret = NULL; if( ap && (dirp = opendir(ap)) ) { const int STEP = 5; struct dirent* dp = NULL; int max = 0; int* pLen = NULL; ret = malloc(sizeof(*ret)); if( ret ) { pLen = (int*)&ret->length; *pLen = 0; } while( pLen && ((dp = readdir(dirp)) != NULL) ) { if( *pLen == max ) { max = max + STEP; ret = realloc(ret, sizeof(*ret) + sizeof(RowInfo) * max); pLen = (int*)&ret->length; } if( ret && ((type == TypeAll) || (type == dp->d_type)) ) { if( !IsDotPath(dp->d_name) && MakeEntryItem(&ret->data[*pLen], dp, ap, req) ) { *pLen = *pLen + 1; } } } SortFileEntry(ret); } free(ap); closedir(dirp); return ret;}static char* MakeHTML(const char* req, const char* root){ char* ret = NULL; Table* table = CreateTable(); if( table ) { FileEntry* fe = NULL; char* ts = NULL; char* resp = NULL; RowInfo* back = NULL; int i = 0; if( (strcmp(req, "/") != 0) && (back = calloc(1, sizeof(*back))) ) { i = strlen(req) - 1; strcpy(back->link, req); while( back->link[i] != '/' ) i--; i ? (back->link[i] = 0) : (back->link[i+1] = 0); strcpy(back->name, "./.."); strcpy(back->type, "Back.."); table = InsertRow(table, back); } free(back); fe = GetEntry(req, root, TypeDir); for(i=0; fe && (i<fe->length); i++) { table = InsertRow(table, &fe->data[i]); } free(fe); fe = GetEntry(req, root, TypeFile); for(i=0; fe && (i<fe->length); i++) { table = InsertRow(table, &fe->data[i]); } free(fe); ts = ToTableString(table); ret = ts ? ToPageString(req, ts) : NULL; free(ts); } FreeTable(table); return ret;}static int Response(TcpClient* client, const char* html){ const char* HTTP_FORMAT = "HTTP/1.1 200 OK\r\n" "Server:Test Http Server\r\n" "Content-Length:%d\r\n" "Content-Type:text/html\r\n" "Connection:close\r\n\r\n" "%s"; int ret = 0; if( html ) { char* resp = malloc(strlen(HTTP_FORMAT) + strlen(html) + 16); if( resp ) { sprintf(resp, HTTP_FORMAT, strlen(html), html); ret = (TcpClient_SendRaw(client, resp, strlen(resp)) > 0); } free(resp); } return ret;}static int DirReqHandler(TcpClient* client, const char* req, const char* root){ char* html = MakeHTML(req, root); int ret = Response(client, html); free(html); return ret;}int RequestHandler(TcpClient* client, const char* req, const char* root){ int ret = 0; if( client && req && root ) { ret = DirReqHandler(client, req, root); } return ret;}
思考
favicon.ico 是什么?如何解决?