1 /*
2 * Copyright (C) 2015 Michael Brown <mbrown@fensystems.co.uk>.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 * 02110-1301, USA.
18 *
19 * You can also choose to distribute this program under the terms of
20 * the Unmodified Binary Distribution Licence (as given in the file
21 * COPYING.UBDL), provided that you have satisfied its requirements.
22 */
23
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25
26 #include <stdio.h>
27 #include <ipxe/http.h>
28 #include <ipxe/peermux.h>
29
30 /** @file
31 *
32 * Peer Content Caching and Retrieval (PeerDist) protocol
33 *
34 * This is quite possibly the ugliest protocol I have ever had the
35 * misfortune to encounter, and I've encountered multicast TFTP.
36 */
37
38 /**
39 * Check whether or not to support PeerDist encoding for this request
40 *
41 * @v http HTTP transaction
42 * @ret supported PeerDist encoding is supported for this request
43 */
http_peerdist_supported(struct http_transaction * http)44 static int http_peerdist_supported ( struct http_transaction *http ) {
45
46 /* Support PeerDist encoding only if we can directly access an
47 * underlying data transfer buffer. Direct access is required
48 * in order to support decryption of data received via the
49 * retrieval protocol (which provides the AES initialisation
50 * vector only after all of the encrypted data has been
51 * received).
52 *
53 * This test simultaneously ensures that we do not attempt to
54 * use PeerDist encoding on a request which is itself a
55 * PeerDist individual block download, since the individual
56 * block downloads do not themselves provide direct access to
57 * an underlying data transfer buffer.
58 */
59 return ( xfer_buffer ( &http->xfer ) != NULL );
60 }
61
62 /**
63 * Format HTTP "X-P2P-PeerDist" header
64 *
65 * @v http HTTP transaction
66 * @v buf Buffer
67 * @v len Length of buffer
68 * @ret len Length of header value, or negative error
69 */
http_format_p2p_peerdist(struct http_transaction * http,char * buf,size_t len)70 static int http_format_p2p_peerdist ( struct http_transaction *http,
71 char *buf, size_t len ) {
72 int supported = http_peerdist_supported ( http );
73 int missing;
74
75 /* PeerDist wants us to inform the server whenever we make a
76 * request for data that was missing from local peers
77 * (presumably for statistical purposes only). We use the
78 * heuristic of assuming that the combination of "this request
79 * may not itself use PeerDist content encoding" and "this is
80 * a range request" probably indicates that we are making a
81 * PeerDist block raw range request for missing data.
82 */
83 missing = ( http->request.range.len && ( ! supported ) );
84
85 /* Omit header if PeerDist encoding is not supported and we
86 * are not reporting a missing data request.
87 */
88 if ( ! ( supported || missing ) )
89 return 0;
90
91 /* Construct header */
92 return snprintf ( buf, len, "Version=1.1%s",
93 ( missing ? ", MissingDataRequest=true" : "" ) );
94 }
95
96 /** HTTP "X-P2P-PeerDist" header */
97 struct http_request_header http_request_p2p_peerdist __http_request_header = {
98 .name = "X-P2P-PeerDist",
99 .format = http_format_p2p_peerdist,
100 };
101
102 /**
103 * Format HTTP "X-P2P-PeerDistEx" header
104 *
105 * @v http HTTP transaction
106 * @v buf Buffer
107 * @v len Length of buffer
108 * @ret len Length of header value, or negative error
109 */
http_format_p2p_peerdistex(struct http_transaction * http,char * buf,size_t len)110 static int http_format_p2p_peerdistex ( struct http_transaction *http,
111 char *buf, size_t len ) {
112 int supported = http_peerdist_supported ( http );
113
114 /* Omit header if PeerDist encoding is not supported */
115 if ( ! supported )
116 return 0;
117
118 /* Construct header */
119 return snprintf ( buf, len, ( "MinContentInformation=1.0, "
120 "MaxContentInformation=2.0" ) );
121 }
122
123 /** HTTP "X-P2P-PeerDist" header */
124 struct http_request_header http_request_p2p_peerdistex __http_request_header = {
125 .name = "X-P2P-PeerDistEx",
126 .format = http_format_p2p_peerdistex,
127 };
128
129 /**
130 * Initialise PeerDist content encoding
131 *
132 * @v http HTTP transaction
133 * @ret rc Return status code
134 */
http_peerdist_init(struct http_transaction * http)135 static int http_peerdist_init ( struct http_transaction *http ) {
136
137 return peermux_filter ( &http->content, &http->transfer, http->uri );
138 }
139
140 /** PeerDist HTTP content encoding */
141 struct http_content_encoding peerdist_encoding __http_content_encoding = {
142 .name = "peerdist",
143 .supported = http_peerdist_supported,
144 .init = http_peerdist_init,
145 };
146