1 //
2 //
3 // Copyright 2015 gRPC authors.
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 //     http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17 //
18 
19 #include <grpc/support/port_platform.h>
20 
21 #include "src/core/lib/http/format_request.h"
22 
23 #include <stdio.h>
24 #include <string.h>
25 
26 #include <algorithm>
27 #include <initializer_list>
28 #include <string>
29 #include <vector>
30 
31 #include "absl/strings/str_cat.h"
32 #include "absl/strings/str_format.h"
33 #include "absl/strings/str_join.h"
34 #include "absl/strings/string_view.h"
35 
36 #include <grpc/slice.h>
37 
38 #include "src/core/lib/http/httpcli.h"
39 
fill_common_header(const grpc_http_request * request,const char * host,const char * path,bool connection_close,std::vector<std::string> * buf)40 static void fill_common_header(const grpc_http_request* request,
41                                const char* host, const char* path,
42                                bool connection_close,
43                                std::vector<std::string>* buf) {
44   buf->push_back(path);
45   buf->push_back(" HTTP/1.1\r\n");
46   buf->push_back("Host: ");
47   buf->push_back(host);
48   buf->push_back("\r\n");
49   if (connection_close) buf->push_back("Connection: close\r\n");
50   buf->push_back("User-Agent: " GRPC_HTTPCLI_USER_AGENT "\r\n");
51   // user supplied headers
52   for (size_t i = 0; i < request->hdr_count; i++) {
53     buf->push_back(request->hdrs[i].key);
54     buf->push_back(": ");
55     buf->push_back(request->hdrs[i].value);
56     buf->push_back("\r\n");
57   }
58 }
59 
grpc_httpcli_format_get_request(const grpc_http_request * request,const char * host,const char * path)60 grpc_slice grpc_httpcli_format_get_request(const grpc_http_request* request,
61                                            const char* host, const char* path) {
62   std::vector<std::string> out;
63   out.push_back("GET ");
64   fill_common_header(request, host, path, true, &out);
65   out.push_back("\r\n");
66   std::string req = absl::StrJoin(out, "");
67   return grpc_slice_from_copied_buffer(req.data(), req.size());
68 }
69 
grpc_httpcli_format_post_request(const grpc_http_request * request,const char * host,const char * path)70 grpc_slice grpc_httpcli_format_post_request(const grpc_http_request* request,
71                                             const char* host,
72                                             const char* path) {
73   std::vector<std::string> out;
74   out.push_back("POST ");
75   fill_common_header(request, host, path, true, &out);
76   if (request->body != nullptr) {
77     bool has_content_type = false;
78     for (size_t i = 0; i < request->hdr_count; i++) {
79       if (strcmp(request->hdrs[i].key, "Content-Type") == 0) {
80         has_content_type = true;
81         break;
82       }
83     }
84     if (!has_content_type) {
85       out.push_back("Content-Type: text/plain\r\n");
86     }
87     out.push_back(
88         absl::StrFormat("Content-Length: %lu\r\n",
89                         static_cast<unsigned long>(request->body_length)));
90   }
91   out.push_back("\r\n");
92   std::string req = absl::StrJoin(out, "");
93   if (request->body != nullptr) {
94     absl::StrAppend(&req,
95                     absl::string_view(request->body, request->body_length));
96   }
97   return grpc_slice_from_copied_buffer(req.data(), req.size());
98 }
99 
grpc_httpcli_format_put_request(const grpc_http_request * request,const char * host,const char * path)100 grpc_slice grpc_httpcli_format_put_request(const grpc_http_request* request,
101                                            const char* host, const char* path) {
102   std::vector<std::string> out;
103   out.push_back("PUT ");
104   fill_common_header(request, host, path, true, &out);
105   if (request->body != nullptr) {
106     bool has_content_type = false;
107     for (size_t i = 0; i < request->hdr_count; i++) {
108       if (strcmp(request->hdrs[i].key, "Content-Type") == 0) {
109         has_content_type = true;
110         break;
111       }
112     }
113     if (!has_content_type) {
114       out.push_back("Content-Type: text/plain\r\n");
115     }
116     out.push_back(
117         absl::StrFormat("Content-Length: %lu\r\n",
118                         static_cast<unsigned long>(request->body_length)));
119   }
120   out.push_back("\r\n");
121   std::string req = absl::StrJoin(out, "");
122   if (request->body != nullptr) {
123     absl::StrAppend(&req,
124                     absl::string_view(request->body, request->body_length));
125   }
126   return grpc_slice_from_copied_buffer(req.data(), req.size());
127 }
128 
grpc_httpcli_format_connect_request(const grpc_http_request * request,const char * host,const char * path)129 grpc_slice grpc_httpcli_format_connect_request(const grpc_http_request* request,
130                                                const char* host,
131                                                const char* path) {
132   std::vector<std::string> out;
133   out.push_back("CONNECT ");
134   fill_common_header(request, host, path, false, &out);
135   out.push_back("\r\n");
136   std::string req = absl::StrJoin(out, "");
137   return grpc_slice_from_copied_buffer(req.data(), req.size());
138 }
139