blob: 196b666d876b3774b5ade6423bd38e749dcb4c72 [file] [log] [blame]
Constantin Ziesche857c7ab2020-02-25 11:24:51 +01001/*******************************************************************************
2* Copyright (c) 2020 Robert Bosch GmbH
3* Author: Constantin Ziesche (constantin.ziesche@bosch.com)
4*
5* This program and the accompanying materials are made available under the
6* terms of the Eclipse Public License 2.0 which is available at
7* http://www.eclipse.org/legal/epl-2.0
8*
9* SPDX-License-Identifier: EPL-2.0
10*******************************************************************************/
Constantin Ziesche08215502020-09-21 19:08:32 +020011using BaSyx.Utils.JsonHandling;
Constantin Ziesche857c7ab2020-02-25 11:24:51 +010012using BaSyx.Utils.ResultHandling;
13using BaSyx.Utils.Settings.Sections;
14using Newtonsoft.Json;
Constantin Ziesche857c7ab2020-02-25 11:24:51 +010015using System;
16using System.Collections.Generic;
17using System.Net;
18using System.Net.Http;
Constantin Ziesche09dcb6b2020-10-07 13:47:39 +020019using System.Net.Security;
20using System.Security.Cryptography.X509Certificates;
Constantin Ziesche857c7ab2020-02-25 11:24:51 +010021using System.Text;
22using System.Threading.Tasks;
23
24namespace BaSyx.Utils.Client.Http
25{
Constantin Ziesche09dcb6b2020-10-07 13:47:39 +020026 public abstract class SimpleHttpClient : IDisposable
Constantin Ziesche857c7ab2020-02-25 11:24:51 +010027 {
28 public HttpClient HttpClient { get; }
29 public HttpClientHandler HttpClientHandler { get; }
30 public JsonSerializerSettings JsonSerializerSettings { get; protected set; }
31
Constantin Ziesche09dcb6b2020-10-07 13:47:39 +020032 public const int DEFAULT_REQUEST_TIMEOUT = 30000;
Constantin Ziesche7b6d4792020-08-18 17:15:11 +020033
Constantin Ziesche09dcb6b2020-10-07 13:47:39 +020034 public static HttpClientHandler DEFAULT_HTTP_CLIENT_HANDLER
Constantin Ziesche857c7ab2020-02-25 11:24:51 +010035 {
Constantin Ziesche09dcb6b2020-10-07 13:47:39 +020036 get
37 {
38 return new HttpClientHandler()
39 {
40 MaxConnectionsPerServer = 100,
41 AllowAutoRedirect = true,
42 UseProxy = false,
43 ServerCertificateCustomValidationCallback = Validate
44 };
45 }
46 }
47
48 private static bool Validate(HttpRequestMessage message, X509Certificate2 cert, X509Chain chain, SslPolicyErrors policyErrors)
49 {
50 return true;
51 }
52
53 protected SimpleHttpClient(HttpClientHandler clientHandler)
54 {
55 if (clientHandler == null)
56 clientHandler = DEFAULT_HTTP_CLIENT_HANDLER;
57
58 HttpClientHandler = clientHandler;
59 HttpClient = new HttpClient(HttpClientHandler, true);
Constantin Ziesche857c7ab2020-02-25 11:24:51 +010060
Constantin Ziesche08215502020-09-21 19:08:32 +020061 JsonSerializerSettings = new DefaultJsonSerializerSettings();
Constantin Ziesche857c7ab2020-02-25 11:24:51 +010062 }
63
64 protected virtual void LoadProxy(ProxyConfiguration proxyConfiguration)
65 {
66 if (proxyConfiguration == null)
67 return;
68
69 if (proxyConfiguration.UseProxy && !string.IsNullOrEmpty(proxyConfiguration.ProxyAddress))
70 {
71 HttpClientHandler.UseProxy = true;
72 if (!string.IsNullOrEmpty(proxyConfiguration.UserName) && !string.IsNullOrEmpty(proxyConfiguration.Password))
73 {
74 NetworkCredential credential;
75 if (!string.IsNullOrEmpty(proxyConfiguration.Domain))
76 credential = new NetworkCredential(proxyConfiguration.UserName, proxyConfiguration.Password, proxyConfiguration.Domain);
77 else
78 credential = new NetworkCredential(proxyConfiguration.UserName, proxyConfiguration.Password);
79
80 HttpClientHandler.Proxy = new WebProxy(proxyConfiguration.ProxyAddress, false, null, credential);
81 }
82 else
83 HttpClientHandler.Proxy = new WebProxy(proxyConfiguration.ProxyAddress);
84 }
85 else
86 HttpClientHandler.UseProxy = false;
87 }
88
89 protected virtual IResult<HttpResponseMessage> SendRequest(HttpRequestMessage message, int timeout)
90 {
91 try
92 {
93 var task = HttpClient.SendAsync(message);
94 if (Task.WhenAny(task, Task.Delay(timeout)).Result == task)
95 {
96 return new Result<HttpResponseMessage>(true, task.Result);
97 }
98 else
99 {
100 return new Result<HttpResponseMessage>(false, new List<IMessage> { new Message(MessageType.Error, "Error while sending the request: timeout") });
101 }
102 }
103 catch (Exception e)
104 {
105 return new Result<HttpResponseMessage>(e);
106 }
107 }
108
Constantin Ziesche310d2aa2020-03-25 11:48:26 +0100109 protected virtual async Task<IResult<HttpResponseMessage>> SendRequestAsync(HttpRequestMessage message)
110 {
111 try
112 {
113 using(HttpResponseMessage response = await HttpClient.SendAsync(message).ConfigureAwait(false))
114 return new Result<HttpResponseMessage>(true, response);
115 }
116 catch (Exception e)
117 {
118 return new Result<HttpResponseMessage>(e);
119 }
120 }
121
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100122 protected virtual HttpRequestMessage CreateRequest(Uri uri, HttpMethod method)
123 {
124 return new HttpRequestMessage(method, uri);
125 }
126
127 protected virtual HttpRequestMessage CreateRequest(Uri uri, HttpMethod method, HttpContent content)
128 {
129 var message = CreateRequest(uri, method);
130 if (content != null)
131 message.Content = content;
132
133 return message;
134 }
135
136 protected virtual HttpRequestMessage CreateJsonContentRequest(Uri uri, HttpMethod method, object content)
137 {
138 var message = CreateRequest(uri, method, () =>
139 {
140 var serialized = JsonConvert.SerializeObject(content, JsonSerializerSettings);
141 return new StringContent(serialized, Encoding.UTF8, "application/json");
142 });
143 return message;
144 }
145
146 protected virtual HttpRequestMessage CreateRequest(Uri uri, HttpMethod method, Func<HttpContent> content)
147 {
148 var message = CreateRequest(uri, method);
149 if (content != null)
150 message.Content = content.Invoke();
151
152 return message;
153 }
154
155 protected virtual IResult EvaluateResponse(IResult result, HttpResponseMessage response)
156 {
Constantin Ziesche09dcb6b2020-10-07 13:47:39 +0200157 List<IMessage> messageList = new List<IMessage>();
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100158 messageList.AddRange(result.Messages);
159
160 if (response != null)
161 {
Constantin Ziesche09dcb6b2020-10-07 13:47:39 +0200162 byte[] responseByteArray = response.Content.ReadAsByteArrayAsync().Result;
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100163 if (response.IsSuccessStatusCode)
164 {
165 messageList.Add(new Message(MessageType.Information, response.ReasonPhrase, ((int)response.StatusCode).ToString()));
Constantin Ziesche09dcb6b2020-10-07 13:47:39 +0200166 return new Result(true, responseByteArray, typeof(byte[]), messageList);
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100167 }
168 else
169 {
Constantin Ziesche09dcb6b2020-10-07 13:47:39 +0200170 string responseString = string.Empty;
171 if(responseByteArray?.Length > 0)
172 responseString = Encoding.UTF8.GetString(responseByteArray);
173
Constantin Ziesche310d2aa2020-03-25 11:48:26 +0100174 messageList.Add(new Message(MessageType.Error, response.ReasonPhrase + " | " + responseString, ((int)response.StatusCode).ToString()));
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100175 return new Result(false, messageList);
176 }
177 }
178 messageList.Add(new Message(MessageType.Error, "Evaluation of response failed - Response from host is null", null));
179 return new Result(false, messageList);
180 }
181
182 protected virtual IResult<T> EvaluateResponse<T>(IResult result, HttpResponseMessage response)
183 {
Constantin Ziesche09dcb6b2020-10-07 13:47:39 +0200184 List<IMessage> messageList = new List<IMessage>();
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100185 messageList.AddRange(result.Messages);
186
187 if (response != null)
188 {
Constantin Ziesche09dcb6b2020-10-07 13:47:39 +0200189 string responseString = response.Content.ReadAsStringAsync().Result;
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100190 if (response.IsSuccessStatusCode)
191 {
192 try
193 {
Constantin Ziesche7b6d4792020-08-18 17:15:11 +0200194 T requestResult = JsonConvert.DeserializeObject<T>(responseString, JsonSerializerSettings);
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100195
196 messageList.Add(new Message(MessageType.Information, response.ReasonPhrase, ((int)response.StatusCode).ToString()));
197 return new Result<T>(true, requestResult, messageList);
198 }
199 catch (Exception e)
200 {
Constantin Ziesche7b6d4792020-08-18 17:15:11 +0200201 messageList.Add(new ExceptionMessage(e));
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100202 return new Result<T>(false, messageList);
203 }
204 }
205 else
206 {
Constantin Ziesche310d2aa2020-03-25 11:48:26 +0100207 messageList.Add(new Message(MessageType.Error, response.ReasonPhrase + " | " + responseString, ((int)response.StatusCode).ToString()));
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100208 return new Result<T>(false, messageList);
209 }
210 }
211 messageList.Add(new Message(MessageType.Error, "Evaluation of response failed - Response from host is null", null));
212 return new Result<T>(false, messageList);
213 }
Constantin Ziesche09dcb6b2020-10-07 13:47:39 +0200214
215 #region IDisposable Support
216 private bool disposedValue = false;
217
218 protected virtual void Dispose(bool disposing)
219 {
220 if (!disposedValue)
221 {
222 if (disposing)
223 {
224 HttpClient.Dispose();
225 }
226 disposedValue = true;
227 }
228 }
229
230 public void Dispose()
231 {
232 Dispose(true);
233 }
234 #endregion
235
236
Constantin Ziesche857c7ab2020-02-25 11:24:51 +0100237 }
238}