问题:浏览器与文件服务器如何交互?

浏览器与文件服务器的交互

  • 文件浏览

    • 点击列表中的文件夹 → 进入子文件夹(展现子文件夹列表)
  • 文件下载

    • 点击列表中的文件 → 下载指标文件
  • 错误处理

    • 向服务器发送谬误申请 → 浏览不存在的文件夹 / 下载不存在的文件

文件浏览交互实现

实现中的要害概念

  • 共享文件夹(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 是什么?如何解决?