Add request type(/m3u) for Vu+PlayerHD (IOS).
[vuplus_transtreamproxy] / src / Http.cpp
1 /*
2  * Http.cpp
3  *
4  *  Created on: 2014. 6. 18.
5  *      Author: oskwon
6  */
7
8 #include <string.h>
9
10 #include <sstream>
11
12 #include "Util.h"
13 #include "Logger.h"
14
15 #include "Http.h"
16 #include "UriDecoder.h"
17
18 using namespace std;
19 //----------------------------------------------------------------------
20
21 bool HttpHeader::parse_request(std::string header)
22 {
23         std::string line, key, value;
24         std::istringstream request_stream;
25         request_stream.str(header);
26
27         request_stream >> method;
28         request_stream >> path;
29         request_stream >> version;
30         std::getline(request_stream, line);
31
32         while(std::getline(request_stream, line)) {
33                 if ((line = Util::trim(line)) != "") {
34                         Util::split_key_value(line, ":", key, value);
35
36                         key   = Util::trim(key);
37                         value = Util::trim(value);
38
39                         params[key] = value;
40                         DEBUG("add param : [%s] - [%s]", key.c_str(), value.c_str());
41                 }
42         }
43
44         int idx = path.find("?");
45         // page
46         if (idx != std::string::npos) {
47                 page = path.substr(0,idx);
48                 std::string page_param = path.substr(idx + 1);
49
50                 DEBUG("request url : [%s] - [%s]", page.c_str(), page_param.c_str());
51                 std::istringstream request_params_stream;
52                 request_params_stream.str(page_param);
53                 while(std::getline(request_params_stream, line, '&')) {
54                         if ((line = Util::trim(line)) != "") {
55                                 Util::split_key_value(line, "=", key, value);
56
57                                 key   = Util::trim(key);
58                                 value = Util::trim(value);
59
60                                 page_params[key] = value;
61                                 DEBUG("add page param : [%s] - [%s]", key.c_str(), value.c_str());
62                         }
63                 }
64
65                 if (page == "/file") {
66                         type = HttpHeader::TRANSCODING_FILE;
67                 }
68                 else if (page == "/m3u") {
69                         type = HttpHeader::M3U;
70                 }
71         }
72         // live
73         else {
74                 type = HttpHeader::TRANSCODING_LIVE;
75         }
76         return true;
77 }
78 //----------------------------------------------------------------------
79
80 static const char *http_ok          = "HTTP/1.1 200 OK\r\n";
81 static const char *http_partial     = "HTTP/1.1 206 Partial Content\r\n";
82 static const char *http_connection  = "Connection: Close\r\n";
83 static const char *http_server      = "Server: transtreamproxy\r\n";
84 static const char *http_done        = "\r\n";
85 std::string HttpHeader::build_response(Mpeg *source)
86 {
87         std::ostringstream oss;
88
89         switch(type) {
90         case HttpHeader::TRANSCODING_FILE: {
91                         std::string range = params["Range"];
92                         off_t seek_offset = 0, content_length = 0;
93
94                         if((range.length() > 7) && (range.substr(0, 6) == "bytes=")) {
95                                 range = range.substr(6);
96                                 if(range.find('-') == (range.length() - 1)) {
97                                         seek_offset = Util::strtollu(range);
98                                 }
99                         }
100
101                         content_length = source->stream_length - seek_offset;
102                         if (seek_offset > 0) {
103                                 content_length += 1;
104                                 oss << http_partial;
105                         }
106                         else {
107                                 oss << http_ok;
108                         }
109                         oss << http_connection;
110                         oss << "Content-Type: video/mpeg\r\n";
111                         oss << http_server;
112                         oss << "Accept-Ranges: bytes\r\n";
113                         oss << "Content-Length: " << Util::ultostr(content_length) << "\r\n";
114                         oss << "Content-Range: bytes " <<
115                                         Util::ultostr(seek_offset) << "-" <<
116                                         Util::ultostr(source->stream_length - 1) << "/" <<
117                                         Util::ultostr(source->stream_length) << "\r\n";
118                         oss << http_done;
119                 }
120                 break;
121         case HttpHeader::TRANSCODING_LIVE: {
122                         oss << http_ok;
123                         oss << http_connection;
124                         oss << "Content-Type: video/mpeg\r\n";
125                         oss << http_server;
126                         oss << http_done;
127                 }
128                 break;
129         case HttpHeader::M3U: {
130                         std::ostringstream m3u_oss;
131                         m3u_oss << "#EXTM3U\n";
132                         m3u_oss << "#EXTVLCOPT--http-reconnect=true\n";
133                         m3u_oss << "http://" << params["Host"] << "/file?file=" << page_params["file"];
134                         if (page_params["position"] != "") {
135                                 m3u_oss << "&position=" << page_params["position"];
136                         }
137                         m3u_oss << "\n";
138                         m3u_oss << http_done;
139
140                         std::string m3u_content = m3u_oss.str();
141
142                         oss << http_partial;
143                         oss << "Content-Type: audio/x-mpegurl\r\n";
144                         oss << "Accept-Ranges: bytes\r\n";
145                         oss << http_connection;
146                         oss << http_server;
147                         oss << "Content-Length: " << Util::ultostr(m3u_content.length()) << "\r\n";
148                         oss << "Content-Range: bytes 0-" <<
149                                         Util::ultostr(m3u_content.length() - 1) << "/" <<
150                                         Util::ultostr(m3u_content.length()) << "\r\n";
151                         oss << http_done;
152                         oss << m3u_content;
153                 }
154                 break;
155         default: return "";
156         }
157         return oss.str();
158 }
159 //----------------------------------------------------------------------
160
161 std::string HttpHeader::read_request()
162 {
163         std::string request = "";
164         while (true) {
165                 char buffer[128] = {0};
166                 fgets(buffer, 127, stdin);
167
168                 request += buffer;
169                 if(request.find("\r\n\r\n") != string::npos)
170                         break;
171         }
172         return request;
173 }
174 //----------------------------------------------------------------------