HttpBody.h 5.59 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
/*
 * MIT License
 *
 * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com>
 *
 * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit).
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#ifndef ZLMEDIAKIT_FILEREADER_H
#define ZLMEDIAKIT_FILEREADER_H

#include <stdlib.h>
#include <memory>
#include "Network/Buffer.h"
#include "Util/ResourcePool.h"
#include "Util/logger.h"
35
#include "Thread/WorkThreadPool.h"
36 37 38 39 40 41 42 43 44 45 46 47 48

using namespace std;
using namespace toolkit;

#ifndef MIN
#define MIN(a,b) ((a) < (b) ? (a) : (b) )
#endif //MIN

namespace mediakit {

/**
 * http content部分基类定义
 */
49
class HttpBody : public std::enable_shared_from_this<HttpBody>{
50 51
public:
    typedef std::shared_ptr<HttpBody> Ptr;
52
    HttpBody(){
xiongziliang committed
53
//        _async_read_thread = WorkThreadPool::Instance().getPoller();
54
    }
55 56 57
    virtual ~HttpBody(){}

    /**
58
     * 剩余数据大小,如果返回>=INT64_MAX, 那么就不设置content-length
59
     */
60
    virtual uint64_t remainSize() { return 0;};
61 62 63 64

    /**
     * 读取一定字节数,返回大小可能小于size
     * @param size 请求大小
65
     * @return 字节对象,如果读完了,那么请返回nullptr
66
     */
67
    virtual Buffer::Ptr readData(uint32_t size) { return nullptr;};
68 69 70 71 72 73 74

    /**
     * 异步请求读取一定字节数,返回大小可能小于size
     * @param size 请求大小
     * @param cb 回调函数
     */
    virtual void readDataAsync(uint32_t size,const function<void(const Buffer::Ptr &buf)> &cb){
75
#if 0
76 77 78 79 80 81 82 83 84 85 86 87 88
        if(size >= remainSize()){
            //假如剩余数据很小,那么同步获取(为了优化性能)
            cb(readData(size));
            return;
        }
        //如果是大文件,那么后台读取
        weak_ptr<HttpBody> weakSelf = shared_from_this();
        _async_read_thread->async([cb,size,weakSelf](){
            auto strongSelf = weakSelf.lock();
            if(strongSelf){
                cb(strongSelf->readData(size));
            }
        });
89 90 91 92 93 94
#else
        //由于unix和linux是通过mmap的方式读取文件,所以把读文件操作放在后台线程并不能提高性能
        //反而会由于频繁的线程切换导致性能降低以及延时增加,所以我们默认同步获取文件内容
        //(其实并没有读,拷贝文件数据时在内核态完成文件读)
        cb(readData(size));
#endif
95 96
    }
private:
xiongziliang committed
97
//    EventPoller::Ptr _async_read_thread;
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
};

/**
 * string类型的content
 */
class HttpStringBody : public HttpBody{
public:
    typedef std::shared_ptr<HttpStringBody> Ptr;
    HttpStringBody(const string &str);
    virtual ~HttpStringBody(){}
    uint64_t remainSize() override ;
    Buffer::Ptr readData(uint32_t size) override ;
private:
    mutable string _str;
    uint64_t _offset = 0;
};

/**
 * 文件类型的content
 */
class HttpFileBody : public HttpBody{
public:
    typedef std::shared_ptr<HttpFileBody> Ptr;

    /**
     * 构造函数
     * @param fp 文件句柄,文件的偏移量必须为0
     * @param offset 相对文件头的偏移量
     * @param max_size 最大读取字节数,未判断是否大于文件真实大小
     */
    HttpFileBody(const std::shared_ptr<FILE> &fp,uint64_t offset,uint64_t max_size);
129
    HttpFileBody(const string &file_path);
130 131 132 133 134
    ~HttpFileBody(){};

    uint64_t remainSize() override ;
    Buffer::Ptr readData(uint32_t size) override;
private:
135 136
    void init(const std::shared_ptr<FILE> &fp,uint64_t offset,uint64_t max_size);
private:
137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178
    std::shared_ptr<FILE> _fp;
    uint64_t _max_size;
    uint64_t _offset = 0;
    std::shared_ptr<char> _map_addr;
    ResourcePool<BufferRaw> _pool;
};

class HttpArgs;

/**
 * http MultiForm 方式提交的http content
 */
class HttpMultiFormBody : public HttpBody {
public:
    typedef std::shared_ptr<HttpMultiFormBody> Ptr;

    /**
     * 构造函数
     * @param args http提交参数列表
     * @param filePath 文件路径
     * @param boundary boundary字符串
     */
    HttpMultiFormBody(const HttpArgs &args,const string &filePath,const string &boundary = "0xKhTmLbOuNdArY");
    virtual ~HttpMultiFormBody(){}
    uint64_t remainSize() override ;
    Buffer::Ptr readData(uint32_t size) override;
public:
    static string multiFormBodyPrefix(const HttpArgs &args,const string &boundary,const string &fileName);
    static string multiFormBodySuffix(const string &boundary);
    static uint64_t fileSize(FILE *fp);
    static string multiFormContentType(const string &boundary);
private:
    string _bodyPrefix;
    string _bodySuffix;
    uint64_t _offset = 0;
    uint64_t _totalSize;
    HttpFileBody::Ptr _fileBody;
};

}//namespace mediakit

#endif //ZLMEDIAKIT_FILEREADER_H