Name | Executed | Routines | % | Executed | Lines | % | Unexecuted |
/home/matt/eu/rds/include/std/net/common.e | 3 | 3 | 100.00% | 39 | 42 | 92.86% | 3 |
Routine | Executed | Lines | Unexecuted | |
parse_url() | 11 | 14 | 78.57% | 3 |
is_inetaddr() | 2 | 2 | 100.00% | 0 |
parse_ip_address() | 13 | 13 | 100.00% | 0 |
# | Executed | |
1 | --**** | |
2 | -- == Common Internet Routines | |
3 | ||
4 | -- Copyright (c) 2009 by OpenEuphoria Group. | |
5 | ||
6 | namespace common | |
7 | ||
8 | include std/regex.e as re | |
9 | include std/sequence.e as seq | |
10 | include std/get.e | |
11 | ||
12 | constant | |
13 | 4 | DEFAULT_PORT=80, |
14 | 4 | re_ip = re:new("""^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])(\:[0-9]+)?$"""), |
15 | 4 | re_http_url = re:new("""(http|https|ftp|ftps|gopher|gophers)://([^/]+)(/[^?]+)?(\?.*)?""", re:CASELESS), |
16 | 4 | re_mail_url = re:new("""(mailto):(([^@]+)@([^?]+))(\?.*)?""") |
17 | ||
18 | --**** | |
19 | -- === IP Address Handling | |
20 | ||
21 | --** | |
22 | -- Checks if x is an IP address in the form (#.#.#.#[:#]) | |
23 | -- | |
24 | -- Parameters: | |
25 | -- # ##address## : the address to check | |
26 | -- | |
27 | -- Returns: | |
28 | -- An **integer**, 1 if x is an inetaddr, 0 if it is not | |
29 | -- | |
30 | -- Comments: | |
31 | -- Some ip validation algorithms do not allow 0.0.0.0. We do here because | |
32 | -- many times you will want to bind to 0.0.0.0. However, you cannot connect | |
33 | -- to 0.0.0.0 of course. | |
34 | -- | |
35 | -- With sockets, normally binding to 0.0.0.0 means bind to all interfaces | |
36 | -- that the computer has. | |
37 | -- | |
38 | ||
39 | 12 | |
40 | 12 | return re:is_match(re_ip, address) |
41 | end function | |
42 | ||
43 | --** | |
44 | -- Converts a text "address:port" into {"address", port} format. | |
45 | -- | |
46 | -- Parameters: | |
47 | -- # ##address## : ip address to connect, optionally with :PORT at the end | |
48 | -- # ##port## : optional, if not specified you may include :PORT in | |
49 | -- the address parameter otherwise the default port 80 is used. | |
50 | -- | |
51 | -- Comments: | |
52 | -- If ##port## is supplied, it overrides any ":PORT" value in the input | |
53 | -- address. | |
54 | -- | |
55 | -- Returns: | |
56 | -- A **sequence**, of two elements: "address" and integer port number. | |
57 | -- | |
58 | -- Example 1: | |
59 | -- | |
60 | -- addr = parse_ip_address("11.1.1.1") --> {"11.1.1.1", 80} -- default port | |
61 | -- addr = parse_ip_address("11.1.1.1:110") --> {"11.1.1.1", 110} | |
62 | -- addr = parse_ip_address("11.1.1.1", 345) --> {"11.1.1.1", 345} | |
63 | -- | |
64 | ||
65 | 9 | |
66 | 9 | address = seq:split(':', address) |
67 | ||
68 | 9 | if length(address) = 1 then |
69 | 5 | if port < 0 or port > 65_535 then |
70 | 1 | address &= DEFAULT_PORT |
71 | else | |
72 | 4 | address &= port |
73 | end if | |
74 | else | |
75 | 4 | if port < 0 or port > 65_535 then |
76 | 3 | address[2] = value(address[2]) |
77 | 3 | if address[2][1] != GET_SUCCESS then |
78 | 1 | address[2] = DEFAULT_PORT |
79 | else | |
80 | 2 | address[2] = address[2][2] |
81 | end if | |
82 | else | |
83 | 1 | address[2] = port |
84 | end if | |
85 | end if | |
86 | ||
87 | 9 | return address |
88 | end function | |
89 | ||
90 | --**** | |
91 | -- === URL Parsing | |
92 | -- | |
93 | ||
94 | public constant | |
95 | 4 | URL_ENTIRE = 1, |
96 | 4 | URL_PROTOCOL = 2, |
97 | 4 | URL_HTTP_DOMAIN = 3, |
98 | 4 | URL_HTTP_PATH = 4, |
99 | 4 | URL_HTTP_QUERY = 5, |
100 | 4 | URL_MAIL_ADDRESS = 3, |
101 | 4 | URL_MAIL_USER = 4, |
102 | 4 | URL_MAIL_DOMAIN = 5, |
103 | 4 | URL_MAIL_QUERY = 6 |
104 | ||
105 | --** | |
106 | -- Parse a common URL. Currently supported URLs are http(s), ftp(s), gopher(s) and mailto. | |
107 | -- | |
108 | -- Parameters: | |
109 | -- # ##url## : url to be parsed | |
110 | -- | |
111 | -- Returns: | |
112 | -- A **sequence**, containing the URL details. You should use the ##URL_## constants | |
113 | -- to access the values of the returned sequence. You should first check the | |
114 | -- protocol ([[:URL_PROTOCOL]]) that was returned as the data contained in the | |
115 | -- return value can be of different lengths. | |
116 | -- | |
117 | -- On a parse error, -1 will be returned. | |
118 | -- | |
119 | -- Example 1: | |
120 | -- | |
121 | -- object url_data = parse_url("http://john.com/index.html?name=jeff") | |
122 | -- -- url_data = { | |
123 | -- -- "http://john.com/index.html?name=jeff", -- URL_ENTIRE | |
124 | -- -- "http", -- URL_PROTOCOL | |
125 | -- -- "john.com", -- URL_DOMAIN | |
126 | -- -- "/index.html", -- URL_PATH | |
127 | -- -- "?name=jeff" -- URL_QUERY | |
128 | -- -- } | |
129 | -- | |
130 | -- url_data = parse_url("mailto:john@mail.doe.com?subject=Hello%20John%20Doe") | |
131 | -- -- url_data = { | |
132 | -- -- "mailto:john@mail.doe.com?subject=Hello%20John%20Doe", | |
133 | -- -- "mailto", | |
134 | -- -- "john@mail.doe.com", | |
135 | -- -- "john", | |
136 | -- -- "mail.doe.com", | |
137 | -- -- "?subject=Hello%20John%20Doe" | |
138 | -- -- } | |
139 | -- | |
140 | -- | |
141 | ||
142 | 3 | |
143 | object m | |
144 | ||
145 | 3 | m = re:matches(re_http_url, url) |
146 | 3 | if sequence(m) then |
147 | 1 | if length(m) < URL_HTTP_PATH then |
148 | 0 | m &= { "/" } |
149 | end if | |
150 | 1 | if length(m) < URL_HTTP_QUERY then |
151 | 0 | m &= { "" } |
152 | end if | |
153 | ||
154 | 1 | return m |
155 | end if | |
156 | ||
157 | 2 | m = re:matches(re_mail_url, url) |
158 | 2 | if sequence(m) then |
159 | 1 | if length(m) < URL_MAIL_QUERY then |
160 | 0 | m &= { "" } |
161 | end if | |
162 | ||
163 | 1 | return m |
164 | end if | |
165 | ||
166 | 1 | return re:ERROR_NOMATCH |
167 | end function |