55namespace Redmine \Client ;
66
77use Redmine \Exception \ClientException ;
8+ use Redmine \Http \HttpClient ;
9+ use Redmine \Http \HttpFactory ;
10+ use Redmine \Http \Request ;
11+ use Redmine \Http \Response ;
812
913/**
1014 * Native cURL client.
1115 */
12- final class NativeCurlClient implements Client
16+ final class NativeCurlClient implements Client, HttpClient
1317{
1418 use ClientApiTrait;
1519
@@ -55,6 +59,27 @@ public function __construct(
5559 }
5660 }
5761
62+ /**
63+ * Create and send a HTTP request and return the response
64+ *
65+ * @throws ClientException If anything goes wrong on creating or sending the request
66+ */
67+ public function request (Request $ request ): Response
68+ {
69+ $ this ->runRequest (
70+ $ request ->getMethod (),
71+ $ request ->getPath (),
72+ $ request ->getContent (),
73+ $ request ->getContentType ()
74+ );
75+
76+ return HttpFactory::makeResponse (
77+ $ this ->lastResponseStatusCode ,
78+ $ this ->lastResponseContentType ,
79+ $ this ->lastResponseBody
80+ );
81+ }
82+
5883 /**
5984 * Sets to an existing username so api calls can be
6085 * impersonated to this user.
@@ -77,31 +102,31 @@ public function stopImpersonateUser(): void
77102 */
78103 public function requestGet (string $ path ): bool
79104 {
80- return $ this ->request ( ' get ' , $ path );
105+ return $ this ->runRequest ( ' GET ' , $ path );
81106 }
82107
83108 /**
84109 * Create and send a POST request.
85110 */
86111 public function requestPost (string $ path , string $ body ): bool
87112 {
88- return $ this ->request ( ' post ' , $ path , $ body );
113+ return $ this ->runRequest ( ' POST ' , $ path , $ body );
89114 }
90115
91116 /**
92117 * Create and send a PUT request.
93118 */
94119 public function requestPut (string $ path , string $ body ): bool
95120 {
96- return $ this ->request ( ' put ' , $ path , $ body );
121+ return $ this ->runRequest ( ' PUT ' , $ path , $ body );
97122 }
98123
99124 /**
100125 * Create and send a DELETE request.
101126 */
102127 public function requestDelete (string $ path ): bool
103128 {
104- return $ this ->request ( ' delete ' , $ path );
129+ return $ this ->runRequest ( ' DELETE ' , $ path );
105130 }
106131
107132 /**
@@ -211,13 +236,13 @@ private function unsetHttpHeader(string $name): void
211236 /**
212237 * @throws ClientException If anything goes wrong on curl request
213238 */
214- private function request (string $ method , string $ path , string $ body = '' ): bool
239+ private function runRequest (string $ method , string $ path , string $ body = '' , string $ contentType = '' ): bool
215240 {
216241 $ this ->lastResponseStatusCode = 0 ;
217242 $ this ->lastResponseContentType = '' ;
218243 $ this ->lastResponseBody = '' ;
219244
220- $ curl = $ this ->createCurl ($ method , $ path , $ body );
245+ $ curl = $ this ->createCurl ($ method , $ path , $ body, $ contentType );
221246
222247 $ response = curl_exec ($ curl );
223248
@@ -249,7 +274,7 @@ private function request(string $method, string $path, string $body = ''): bool
249274 *
250275 * @return \CurlHandle a cURL handle on success, <b>FALSE</b> on errors
251276 */
252- private function createCurl (string $ method , string $ path , string $ body = '' )
277+ private function createCurl (string $ method , string $ path , string $ body = '' , string $ contentType = '' )
253278 {
254279 // General cURL options
255280 $ curlOptions = [
@@ -264,13 +289,13 @@ private function createCurl(string $method, string $path, string $body = '')
264289 $ curlOptions [CURLOPT_URL ] = $ this ->url . $ path ;
265290
266291 // Set the HTTP request headers
267- $ curlOptions [CURLOPT_HTTPHEADER ] = $ this ->createHttpHeader ($ path );
292+ $ curlOptions [CURLOPT_HTTPHEADER ] = $ this ->createHttpHeader ($ path, $ contentType );
268293
269294 unset($ curlOptions [CURLOPT_CUSTOMREQUEST ]);
270295 unset($ curlOptions [CURLOPT_POST ]);
271296 unset($ curlOptions [CURLOPT_POSTFIELDS ]);
272297 switch ($ method ) {
273- case 'post ' :
298+ case 'POST ' :
274299 $ curlOptions [CURLOPT_POST ] = 1 ;
275300 if ($ this ->isUploadCall ($ path ) && $ this ->isValidFilePath ($ body )) {
276301 @trigger_error ('Uploading an attachment by filepath is deprecated, use file_get_contents() to upload the file content instead. ' , E_USER_DEPRECATED );
@@ -286,13 +311,13 @@ private function createCurl(string $method, string $path, string $body = '')
286311 $ curlOptions [CURLOPT_POSTFIELDS ] = $ body ;
287312 }
288313 break ;
289- case 'put ' :
314+ case 'PUT ' :
290315 $ curlOptions [CURLOPT_CUSTOMREQUEST ] = 'PUT ' ;
291316 if ($ body !== '' ) {
292317 $ curlOptions [CURLOPT_POSTFIELDS ] = $ body ;
293318 }
294319 break ;
295- case 'delete ' :
320+ case 'DELETE ' :
296321 $ curlOptions [CURLOPT_CUSTOMREQUEST ] = 'DELETE ' ;
297322 break ;
298323 default : // GET
@@ -314,7 +339,7 @@ private function createCurl(string $method, string $path, string $body = '')
314339 return $ curl ;
315340 }
316341
317- private function createHttpHeader (string $ path ): array
342+ private function createHttpHeader (string $ path, string $ contentType = '' ): array
318343 {
319344 // Additional request headers
320345 $ httpHeaders = [
@@ -352,14 +377,18 @@ private function createHttpHeader(string $path): array
352377 // Now set or reset mandatory headers
353378
354379 // Content type headers
355- $ tmp = parse_url ($ this ->url . $ path );
356-
357- if ($ this ->isUploadCall ($ path )) {
358- $ httpHeaders [] = 'Content-Type: application/octet-stream ' ;
359- } elseif ('json ' === substr ($ tmp ['path ' ], -4 )) {
360- $ httpHeaders [] = 'Content-Type: application/json ' ;
361- } elseif ('xml ' === substr ($ tmp ['path ' ], -3 )) {
362- $ httpHeaders [] = 'Content-Type: text/xml ' ;
380+ if ($ contentType !== '' ) {
381+ $ httpHeaders [] = 'Content-Type: ' . $ contentType ;
382+ } else {
383+ $ tmp = parse_url ($ this ->url . $ path );
384+
385+ if ($ this ->isUploadCall ($ path )) {
386+ $ httpHeaders [] = 'Content-Type: application/octet-stream ' ;
387+ } elseif ('json ' === substr ($ tmp ['path ' ], -4 )) {
388+ $ httpHeaders [] = 'Content-Type: application/json ' ;
389+ } elseif ('xml ' === substr ($ tmp ['path ' ], -3 )) {
390+ $ httpHeaders [] = 'Content-Type: text/xml ' ;
391+ }
363392 }
364393
365394 return $ httpHeaders ;
0 commit comments