]> git.sesse.net Git - cubemap/blob - input.cpp
Use accept4() to save a system call. Probably inconsequential, but still nice.
[cubemap] / input.cpp
1 #include <stddef.h>
2 #include <string>
3
4 #include "httpinput.h"
5 #include "input.h"
6 #include "state.pb.h"
7 #include "udpinput.h"
8
9 using namespace std;
10
11 namespace {
12
13 // Does not support passwords, only user:host, since this is really only used
14 // to parse VLC's udp://source@multicastgroup:1234/ syntax (we do not support
15 // even basic auth).
16 void split_user_host(const string &user_host, string *user, string *host)
17 {
18         size_t split = user_host.find("@");
19         if (split == string::npos) {
20                 user->clear();
21                 *host = user_host;
22         } else {
23                 *user = string(user_host.begin(), user_host.begin() + split);
24                 *host = string(user_host.begin() + split + 1, user_host.end());
25         }
26 }
27
28 }  // namespace
29
30 // Extremely rudimentary URL parsing.
31 bool parse_url(const string &url, string *protocol, string *user, string *host, string *port, string *path)
32 {
33         size_t split = url.find("://");
34         if (split == string::npos) {
35                 return false;
36         }
37         *protocol = string(url.begin(), url.begin() + split);
38
39         string rest = string(url.begin() + split + 3, url.end());
40
41         // Split at the first slash, or the first colon that's not within [].
42         bool within_brackets = false;
43         for (split = 0; split < rest.size(); ++split) {
44                 if (rest[split] == '[') {
45                         if (within_brackets) {
46                                 // Can't nest brackets.
47                                 return false;
48                         }
49                         within_brackets = true;
50                 } else if (rest[split] == ']') {
51                         if (!within_brackets) {
52                                 // ] without matching [.
53                                 return false;
54                         }
55                         within_brackets = false;
56                 } else if (rest[split] == '/') {
57                         break;
58                 } else if (rest[split] == ':' && !within_brackets) {
59                         break;
60                 }
61         }
62
63         if (split == rest.size()) {
64                 // http://foo
65                 split_user_host(rest, user, host);
66                 *port = *protocol;
67                 *path = "/";
68                 return true;
69         }
70
71         split_user_host(string(rest.begin(), rest.begin() + split), user, host);
72         char ch = rest[split];  // Colon or slash.
73         rest = string(rest.begin() + split + 1, rest.end());
74
75         if (ch == ':') {
76                 // Parse the port.
77                 split = rest.find_first_of('/');
78                 if (split == string::npos) {
79                         // http://foo:1234
80                         *port = rest;
81                         *path = "/";
82                         return true;
83                 } else {
84                         // http://foo:1234/bar
85                         *port = string(rest.begin(), rest.begin() + split);
86                         *path = string(rest.begin() + split, rest.end());
87                         return true;
88                 }
89         }
90
91         // http://foo/bar
92         *port = *protocol;
93         *path = "/" + rest;
94         return true;
95 }
96
97 Input *create_input(const std::string &url)
98 {
99         string protocol, user, host, port, path;
100         if (!parse_url(url, &protocol, &user, &host, &port, &path)) {
101                 return NULL;
102         }
103         if (protocol == "http") {
104                 return new HTTPInput(url);
105         }
106         if (protocol == "udp") {
107                 return new UDPInput(url);
108         }
109         return NULL;
110 }
111
112 Input *create_input(const InputProto &serialized)
113 {
114         string protocol, user, host, port, path;
115         if (!parse_url(serialized.url(), &protocol, &user, &host, &port, &path)) {
116                 return NULL;
117         }
118         if (protocol == "http") {
119                 return new HTTPInput(serialized);
120         }
121         if (protocol == "udp") {
122                 return new UDPInput(serialized);
123         }
124         return NULL;
125 }
126
127 Input::~Input() {}
128