├── logo.png
├── .gitignore
├── src
└── Ws
│ └── Http
│ ├── Exception.php
│ ├── Watcher
│ └── Exception.php
│ ├── Automated
│ ├── Exception.php
│ ├── CookieStore.php
│ ├── README.md
│ ├── Task.php
│ ├── Task
│ │ ├── Body.php
│ │ └── Request.php
│ ├── Bootstrap.php
│ ├── example.json
│ └── postmanv1.json
│ ├── Method.php
│ ├── Request
│ └── Body.php
│ ├── Response.php
│ ├── Watcher.php
│ ├── ARequest.php
│ └── Request.php
├── tests
├── Ws
│ └── Http
│ │ ├── _json
│ │ ├── freegeoip.net.json
│ │ └── a.automated.json
│ │ ├── Automated.php
│ │ ├── Autohome.php
│ │ └── ATest.php
└── bootstrap.php
├── composer.json
├── LICENSE
└── README.md
/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/toohamster/ws-http/HEAD/logo.png
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /vendor
2 | /tests/data
3 | composer.phar
4 | composer.lock
5 | .DS_Store
6 | Thumbs.db
7 |
--------------------------------------------------------------------------------
/src/Ws/Http/Exception.php:
--------------------------------------------------------------------------------
1 | test();
12 | }
13 |
14 | public function test()
15 | {
16 | output(__METHOD__);
17 | $file = __DIR__ . "/_json/a.automated.json";
18 |
19 | $json = file_get_contents($file);
20 |
21 | $task = Task::parse($json);
22 | // output($task);
23 |
24 | Bootstrap::runTask($task);
25 | }
26 |
27 | }
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "toohamster/ws-http",
3 | "description": "ws-http: Simplified, lightweight HTTP client library",
4 | "keywords": ["http", "ws-http"],
5 | "license": "MIT",
6 | "homepage": "https://github.com/toohamster/ws-http",
7 | "support": {
8 | "issues": "https://github.com/toohamster/ws-http/issues",
9 | "source": "https://github.com/toohamster/ws-http"
10 | },
11 | "authors": [
12 | {
13 | "name": "toohamster",
14 | "email": "449211678@qq.com"
15 | }
16 | ],
17 | "require": {
18 | "php": ">=5.4"
19 | },
20 | "require-dev": {
21 |
22 | },
23 | "autoload": {
24 | "classmap": [],
25 | "files": [],
26 | "psr-4": {"Ws\\Http\\": "src/Ws/Http"}
27 | },
28 | "minimum-stability": "dev"
29 | }
30 |
31 |
--------------------------------------------------------------------------------
/src/Ws/Http/Automated/Task.php:
--------------------------------------------------------------------------------
1 | id = $params['id'];
51 | $obj->name = $params['name'];
52 | $obj->type = (int) $params['type'];
53 | $obj->body = TaskBody::parse($params['body']);
54 |
55 | return $obj;
56 | }
57 |
58 | }
59 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 仓鼠 Xu
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/src/Ws/Http/Automated/Task/Body.php:
--------------------------------------------------------------------------------
1 | setVar($item['name'], $item['value']);
36 | }
37 |
38 | foreach( (array) $params['requests'] as $item )
39 | {
40 | $obj->setRequest($item);
41 | }
42 |
43 | return $obj;
44 | }
45 |
46 | public function setVar($name, $value)
47 | {
48 | $this->vars[$name] = $value;
49 | }
50 |
51 | public function setRequest($request)
52 | {
53 | $this->requests[] = Request::parse($request);;
54 | }
55 |
56 | /**
57 | * 替换查询参数并返回
58 | *
59 | * @param string $value 待替换的参数值
60 | *
61 | * @return string
62 | */
63 | public function varReplace($value)
64 | {
65 | if (is_string($value) && !empty($this->vars)) {
66 | foreach ($this->vars as $key => $val) {
67 | $key = '${' . trim($key) . '}';
68 |
69 | if (empty($val)) {
70 | $val = '';
71 | }
72 | $value = str_ireplace($key, $val, $value);
73 | }
74 | }
75 | return $value;
76 | }
77 |
78 | }
--------------------------------------------------------------------------------
/tests/bootstrap.php:
--------------------------------------------------------------------------------
1 | run();
61 | }
62 |
63 | }
64 |
--------------------------------------------------------------------------------
/src/Ws/Http/Method.php:
--------------------------------------------------------------------------------
1 | $file) {
58 | $data[$name] = call_user_func([__CLASS__, 'File'], $file);
59 | }
60 | }
61 |
62 | return $data;
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/src/Ws/Http/Response.php:
--------------------------------------------------------------------------------
1 | code = intval($curl_info['http_code']);
20 | $this->headers = $this->parseHeaders($headers);
21 | $this->raw_body = $raw_body;
22 | $this->curl_info = $curl_info;
23 |
24 | if (!empty($this->headers['Content-Type']))
25 | {
26 | $ct = trim($this->headers['Content-Type']);
27 | if ( false !== stripos($ct, 'application/json') )
28 | {
29 | // make sure raw_body is the first argument
30 | array_unshift($json_args, $raw_body);
31 |
32 | $json = call_user_func_array('json_decode', $json_args);
33 |
34 | if (json_last_error() === JSON_ERROR_NONE) {
35 | $this->body = $json;
36 | }
37 | }
38 | }
39 | }
40 |
41 | /**
42 | * if PECL_HTTP is not available use a fall back function
43 | *
44 | * thanks to ricardovermeltfoort@gmail.com
45 | * http://php.net/manual/en/function.http-parse-headers.php#112986
46 | * @param string $raw_headers raw headers
47 | * @return array
48 | */
49 | private function parseHeaders($raw_headers)
50 | {
51 | if (function_exists('http_parse_headers')) {
52 | return http_parse_headers($raw_headers);
53 | } else {
54 | $key = '';
55 | $headers = [];
56 |
57 | foreach (explode("\n", $raw_headers) as $i => $h) {
58 | $h = explode(':', $h, 2);
59 |
60 | if (isset($h[1])) {
61 | if (!isset($headers[$h[0]])) {
62 | $headers[$h[0]] = trim($h[1]);
63 | } elseif (is_array($headers[$h[0]])) {
64 | $headers[$h[0]] = array_merge($headers[$h[0]], [trim($h[1])]);
65 | } else {
66 | $headers[$h[0]] = array_merge([$headers[$h[0]]], [trim($h[1])]);
67 | }
68 |
69 | $key = $h[0];
70 | } else {
71 | if (substr($h[0], 0, 1) == "\t") {
72 | $headers[$key] .= "\r\n\t".trim($h[0]);
73 | } elseif (!$key) {
74 | $headers[0] = trim($h[0]);
75 | }
76 | }
77 | }
78 |
79 | return $headers;
80 | }
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/src/Ws/Http/Automated/Bootstrap.php:
--------------------------------------------------------------------------------
1 | name, $task->id);
25 |
26 | $data = [];
27 |
28 | $requests = $task->body->requests;
29 | foreach ($requests as $request)
30 | {
31 | if ($request->isDelay())
32 | {
33 | if ($request->delay > 0)
34 | {
35 | sleep($request->delay);
36 | }
37 | }
38 | else
39 | {
40 | //
41 | try
42 | {
43 | $httpResponse = self::doRequest($request, $task);
44 |
45 | output($httpResponse);
46 | }
47 | catch(GlobalException $ex)
48 | {
49 | output($ex->getMessage());
50 | }
51 |
52 | break;
53 | }
54 | }
55 |
56 | }
57 |
58 | public static function doRequest(TaskRequest $request, Task $task)
59 | {
60 | if ($request->isDelay()) return null;
61 |
62 | output($request->name, $request->id);
63 |
64 | $httpRequest = HttpRequest::create();
65 | if ( $request->authorization )
66 | {
67 | $httpRequest->auth( $task->body->varReplace($request->authorization['type']),
68 | $task->body->varReplace($request->authorization['user']),
69 | $task->body->varReplace($request->authorization['password']));
70 | }
71 |
72 | switch ($request->timeout[0])
73 | {
74 | case 's':
75 | $httpRequest->timeout($task->body->varReplace($request->timeout[1]));
76 | break;
77 | case 'ms':
78 | $httpRequest->timeoutMs($task->body->varReplace($request->timeout[1]));
79 | break;
80 | }
81 |
82 | if ($request->proxy)
83 | {
84 | $httpRequest->proxy($task->body->varReplace($request->proxy['address']),
85 | $task->body->varReplace($request->proxy['port']),
86 | $task->body->varReplace($request->proxy['type']),
87 | $task->body->varReplace($request->proxy['tunnel']));
88 |
89 | if (!empty($request->proxy['auth']))
90 | {
91 | $httpRequest->proxyAuth($task->body->varReplace($request->proxy['auth']['user']),
92 | $task->body->varReplace($request->proxy['auth']['password']),
93 | $task->body->varReplace($request->proxy['auth']['method']));
94 | }
95 | }
96 |
97 | $httpResponse = $httpRequest->send($request->method,
98 | $task->body->varReplace($request->url),
99 | $task->body->varReplace($request->data),
100 | $task->body->varReplace($request->headers));
101 |
102 | return $httpResponse;
103 | }
104 |
105 | }
--------------------------------------------------------------------------------
/tests/Ws/Http/Autohome.php:
--------------------------------------------------------------------------------
1 | dir = __DIR__.'/../../data/autohome';
17 | $this->crawl();
18 | }
19 |
20 | public function crawl()
21 | {
22 | output(__METHOD__);
23 | $httpRequest = HttpRequest::create();
24 | // 1 的车型 有164条, 11的话 可以查出 242条
25 | $url = "http://www.autohome.com.cn/ashx/AjaxIndexCarFind.ashx?type=1";
26 | $httpResponse = $httpRequest->get($url);
27 | $filename = $this->dir . '/branditems.json';
28 |
29 | $raw_body = self::gbk2utf8($httpResponse->raw_body);
30 | file_put_contents($filename, $raw_body);
31 |
32 | $data = json_decode($raw_body, true);
33 | if ( !empty($data) && $data['returncode'] == 0 )
34 | {
35 | foreach ( $data['result']['branditems'] as $branditem )
36 | {
37 | if ( !empty($branditem['id']) )
38 | {
39 | $branditemId = $branditem['id'];
40 | $url = "http://www.autohome.com.cn/ashx/AjaxIndexCarFind.ashx?type=3&value={$branditemId}";
41 | $httpResponse = $httpRequest->get($url);
42 |
43 | $filename = $this->dir . "/branditem-{$branditemId}.json";
44 | $raw_body = self::gbk2utf8($httpResponse->raw_body);
45 | file_put_contents($filename, $raw_body);
46 | sleep(1);
47 |
48 | $data001 = json_decode($raw_body, true);
49 | if ( !empty($data001) && $data001['returncode'] == 0 )
50 | {
51 | foreach ( $data001['result']['factoryitems'] as $factoryitem )
52 | {
53 | if ( !empty($factoryitem['id']) )
54 | {
55 | $factoryitemId = $factoryitem['id'];
56 | if ( !empty($factoryitem['seriesitems']) )
57 | {
58 | foreach ( $factoryitem['seriesitems'] as $seriesitem )
59 | {
60 | if ( !empty($seriesitem['id']) )
61 | {
62 | $seriesitemId = $seriesitem['id'];
63 |
64 | $url = "http://www.autohome.com.cn/ashx/AjaxIndexCarFind.ashx?type=5&value={$seriesitemId}";
65 | $httpResponse = $httpRequest->get($url);
66 |
67 | $filename = $this->dir . "/branditem-{$branditemId}-factoryitem-{$factoryitemId}-seriesitem-{$seriesitemId}.json";
68 | $raw_body = self::gbk2utf8($httpResponse->raw_body);
69 | file_put_contents($filename, $raw_body);
70 | sleep(1);
71 |
72 | $data002 = json_decode($raw_body, true);
73 |
74 | $this->oilAndCars($data002,$httpRequest);
75 |
76 | }
77 | }
78 |
79 | }
80 | }
81 | }
82 | }
83 |
84 | }
85 | }
86 | }
87 |
88 | }
89 |
90 | public function oilAndCars($data, $httpRequest)
91 | {
92 |
93 | if ( !empty($data) && $data['returncode'] == 0 )
94 | {
95 | foreach ( $data['result']['yearitems'] as $yearitem )
96 | {
97 | if ( !empty($yearitem['id']) )
98 | {
99 | $yearitemId = $yearitem['id'];
100 | foreach ( $yearitem['specitems'] as $specitem )
101 | {
102 | if ( !empty($specitem['id']) )
103 | {
104 | $specitemId = $specitem['id'];
105 | // 处理油价
106 | $url = "http://www.autohome.com.cn/ashx/ajaxoil.ashx?type=spec&specId={$specitemId}";
107 |
108 | $httpResponse = $httpRequest->get($url);
109 |
110 | $filename = $this->dir . "/oil-{$specitemId}.json";
111 | $raw_body = self::gbk2utf8($httpResponse->raw_body);
112 | file_put_contents($filename, $raw_body);
113 | sleep(1);
114 |
115 | // 找车
116 | // http://www.autohome.com.cn/spec/18658/#pvareaid=10006
117 | }
118 | }
119 |
120 | }
121 | }
122 | }
123 | }
124 |
125 | private static function gbk2utf8($content)
126 | {
127 | return iconv("GBK", "UTF-8", $content);
128 | }
129 |
130 | }
--------------------------------------------------------------------------------
/src/Ws/Http/Automated/Task/Request.php:
--------------------------------------------------------------------------------
1 | id = $params['id'];
38 | $obj->type = (int) $params['type'];
39 |
40 | switch ($obj->type) {
41 | case 1:
42 | $obj->name = $params['name'];
43 | $obj->url = $params['url'];
44 | $obj->method = strtoupper(trim($params['method']));
45 |
46 | $obj->setAuthorization($params['authorization']);
47 | $obj->setProxy($params['proxy']);
48 | $obj->setTimeout(empty($params['timeout']) ? null : $params['timeout']);
49 |
50 | // 设置默认请求头
51 | // $obj->headers['Content-Type'] = 'text/plain';
52 |
53 | // 处理请求数据
54 | switch ($obj->method)
55 | {
56 | // 这两种类型无需对参数做处理
57 | case Method::GET:
58 | case Method::HEAD:
59 | foreach( (array) $params['data'] as $item )
60 | {
61 | if ( 'text' == $item['type'] )
62 | {
63 | $obj->data[ $item['key'] ] = $item['value'];
64 | }
65 | else
66 | {
67 | // 暂未实现
68 | }
69 | }
70 | break;
71 |
72 | // 只有 PUT,POST,DELETE,OPTIONS,PATCH 支持内容体
73 | case Method::POST:
74 | case Method::PUT:
75 | case Method::DELETE:
76 | case Method::OPTIONS:
77 | $dataMode = strtolower( trim($params['dataMode']) );
78 | switch ($dataMode) {
79 | case 'params':
80 | foreach( (array) $params['data'] as $item )
81 | {
82 | if ( 'text' == $item['type'] )
83 | {
84 | $obj->data[ $item['key'] ] = $item['value'];
85 | }
86 | else if ( 'file' == $item['type'] )
87 | {
88 | $obj->headers['Content-Type'] = 'multipart/form-data';
89 | // file 内容暂不支持
90 | }
91 | }
92 | break;
93 | case 'urlencoded':
94 | $obj->headers['Content-Type'] = 'application/x-www-form-urlencoded';
95 | foreach( (array) $params['data'] as $item )
96 | {
97 | if ( 'text' == $item['type'] )
98 | {
99 | $obj->data[ $item['key'] ] = $item['value'];
100 | }
101 | }
102 | break;
103 |
104 | case 'raw-json':
105 | $obj->headers['Content-Type'] = 'application/json';
106 | $obj->data = $params['data']['value'];
107 | break;
108 | case 'raw-xml':
109 | $obj->headers['Content-Type'] = 'application/xml';
110 | $obj->data = $params['data']['value'];
111 | break;
112 | case 'raw-textxml':
113 | $obj->headers['Content-Type'] = 'text/xml';
114 | $obj->data = $params['data']['value'];
115 | break;
116 | case 'raw-html':
117 | $obj->headers['Content-Type'] = 'text/html';
118 | $obj->data = $params['data']['value'];
119 | break;
120 | case 'raw-text':
121 | $obj->headers['Content-Type'] = 'text/plain';
122 | $obj->data = $params['data']['value'];
123 | break;
124 | case 'raw-binary':
125 | default:
126 | throw new Exception("Not supported request `dataMode`: {$dataMode}");
127 | break;
128 | }
129 |
130 | break;
131 | default:
132 | throw new Exception("Not supported request `method`: {$obj->method}");
133 | break;
134 | }
135 |
136 | // 设置请求头
137 | foreach( (array) $params['headers'] as $key => $val )
138 | {
139 | $obj->headers[$key] = $val;
140 | }
141 |
142 | // 设置断言规则
143 |
144 | // 设置变量提取规则
145 |
146 | break;
147 | case 2:
148 | $obj->delay = (int) $params['delay'];
149 | break;
150 | default:
151 | throw new Exception("Unknown request `type`: {$obj->type}");
152 | break;
153 | }
154 |
155 | return $obj;
156 | }
157 |
158 | /**
159 | * 类型是否为请求间隔
160 | *
161 | * @return boolean
162 | */
163 | public function isDelay()
164 | {
165 | return 2 == $this->type;
166 | }
167 |
168 | public function setAuthorization($authorization=[])
169 | {
170 |
171 | $this->authorization = false;
172 |
173 | if (!empty($authorization) && empty($authorization['type']))
174 | {
175 | $type = trim($authorization['type']);
176 | if ( 'Basic' == $type )
177 | {
178 | $this->authorization = [
179 | 'type' => 'Basic',
180 | 'user' => trim($authorization['user']),
181 | 'password' => $authorization['password'],
182 | ];
183 | }
184 | else
185 | {
186 | $this->headers['Authorization'] = trim($authorization['body']);
187 | }
188 | }
189 | }
190 |
191 | public function setTimeout($timeout)
192 | {
193 | // 默认是 30 秒
194 | $this->timeout = ['s', 30];
195 |
196 | if ( empty($timeout) ) return;
197 |
198 | $timeout = trim($timeout);
199 | if (preg_match('/ms$/i',$timeout))
200 | {
201 | $this->timeout[0] = 'ms';
202 | $timeout = str_ireplace('ms', '', $timeout);
203 | }
204 | else if (preg_match('/s$/i',$timeout))
205 | {
206 | $timeout = str_ireplace('s', '', $timeout);
207 | }
208 | else
209 | {
210 | $timeout = 30;
211 | }
212 |
213 | $timeout = intval(trim($timeout));
214 | if ( $timeout < 1 )
215 | {
216 | $this->timeout = ['s', 30];
217 | }
218 | else
219 | {
220 | $this->timeout[1] = $timeout;
221 | }
222 | }
223 |
224 | public function setProxy($proxy=[])
225 | {
226 | $this->proxy = false;
227 |
228 | if (!empty($proxy) && empty($proxy['type']))
229 | {
230 |
231 | $this->proxy = [
232 | 'address' => trim($proxy['address']),
233 | 'port' => trim($proxy['port']),
234 | 'tunnel' => trim($proxy['tunnel']),
235 | ];
236 |
237 | $type = strtolower( trim($proxy['type']) );
238 |
239 | switch ($type) {
240 | case 'http':
241 | $this->proxy['type'] = CURLPROXY_HTTP;
242 | break;
243 | case 'http1.0':
244 | if ( !defined('CURLPROXY_HTTP_1_0') )
245 | {
246 | throw new Exception("Unknown proxy `type`: {$type}");
247 | }
248 | $this->proxy['type'] = CURLPROXY_HTTP_1_0;
249 | break;
250 | case 'socks4':
251 | $this->proxy['type'] = CURLPROXY_SOCKS4;
252 | break;
253 | case 'socks4a':
254 | if ( !defined('CURLPROXY_SOCKS4A') )
255 | {
256 | throw new Exception("Unknown proxy `type`: {$type}");
257 | }
258 | $this->proxy['type'] = CURLPROXY_SOCKS4A;
259 | break;
260 | case 'socks5':
261 | $this->proxy['type'] = CURLPROXY_SOCKS5;
262 | break;
263 | case 'socks5.hostname':
264 | if ( !defined('CURLPROXY_SOCKS5_HOSTNAME') )
265 | {
266 | throw new Exception("Unknown proxy `type`: {$type}");
267 | }
268 | $this->proxy['type'] = CURLPROXY_SOCKS5_HOSTNAME;
269 | break;
270 | default:
271 | throw new Exception("Unknown proxy `type`: {$type}");
272 | break;
273 | }
274 | }
275 | }
276 |
277 | public function toArray()
278 | {
279 |
280 | if ($this->isDelay())
281 | {
282 | return ['id' => $this->id, 'type' => 2, 'delay' => $this->delay];
283 | }
284 |
285 | return [
286 | 'id' => $this->id, 'type' => 1,
287 | 'name' => $this->name,
288 | 'url' => $this->url,
289 | 'method' => $this->method,
290 | 'authorization' => $this->authorization,
291 | 'proxy' => $this->proxy,
292 | 'timeout' => $this->timeout,
293 | 'headers' => $this->headers,
294 | 'data' => $this->data,
295 | ];
296 | }
297 |
298 | }
--------------------------------------------------------------------------------
/src/Ws/Http/Watcher.php:
--------------------------------------------------------------------------------
1 | response = $response;
22 | }
23 |
24 | public function setResponse(Response $response)
25 | {
26 | $this->response = $response;
27 |
28 | return $this;
29 | }
30 |
31 | public function assertTotalTimeLessThan($assertedTime)
32 | {
33 | $totalTime = $this->response->curl_info['total_time'];
34 |
35 | if (floatval($assertedTime) < floatval($totalTime)) {
36 | throw new Exception("Asserted total time '$assertedTime' is less than '$totalTime'.");
37 | }
38 |
39 | return $this;
40 | }
41 |
42 | public function assertStatusCode($statusCode)
43 | {
44 | $httpCode = $this->response->code;
45 | if (intval($statusCode) !== $httpCode) {
46 | throw new Exception("Asserted status code '$statusCode' does not equal response status code '$httpCode'.");
47 | }
48 |
49 | return $this;
50 | }
51 |
52 | public function assertHeadersExist(array $assertedHeaders = [])
53 | {
54 | $headers = & $this->response->headers;
55 | foreach ($assertedHeaders as $header) {
56 | if (!isset($headers[$header])) {
57 | throw new Exception("Asserted header '$header' is not set.");
58 | }
59 | }
60 |
61 | return $this;
62 | }
63 |
64 | public function assertHeaders(array $assertedHeaders = [])
65 | {
66 | if (isAssoc($assertedHeaders))
67 | {
68 | $headers = & $this->response->headers;
69 |
70 | foreach ($assertedHeaders as $k => $v) {
71 | if (!array_key_exists($k, $headers)) {
72 | throw new Exception("Asserted header '$k' is not set.");
73 | }
74 |
75 | if (is_array($headers[$k])) {
76 | if (!in_array($v, $headers[$k])) {
77 | throw new Exception("Asserted header '$k' exists, but the response header value '$v' is not equal.");
78 | }
79 | } else {
80 | if ($v !== $headers[$k]) {
81 | throw new Exception("Asserted header '$k=$v' does not equal response header '$k={$headers[$k]}'.");
82 | }
83 | }
84 | }
85 | }
86 | else {
87 | $this->assertHeadersExist($assertedHeaders);
88 | }
89 |
90 | return $this;
91 | }
92 |
93 | public function assertBody($assertedBody, $useRegularExpression = false)
94 | {
95 | $body = & $this->response->raw_body;
96 |
97 | if ($assertedBody === 'IS_EMPTY') {
98 | if ($body === false || $body === "") {
99 | return $this;
100 | } else {
101 | throw new Exception("Response body is not empty.");
102 | }
103 | }
104 |
105 | if ($assertedBody === 'IS_VALID_JSON') {
106 | if (json_decode($body) === null) {
107 | throw new Exception("Response body is invalid JSON.");
108 | }
109 |
110 | return $this;
111 | }
112 |
113 | if ($useRegularExpression) {
114 | if (!@preg_match($assertedBody, $body)) {
115 | throw new Exception("Asserted body '$assertedBody' does not match response body of '$body'.");
116 | }
117 | } else {
118 | if (strpos($assertedBody, $body)) {
119 | throw new Exception("Asserted body '$assertedBody' does not equal response body of '$body'.");
120 | }
121 | }
122 |
123 | return $this;
124 | }
125 |
126 | public function assertBodyJson($asserted, $onNotEqualVarExport = false)
127 | {
128 | $body = json_decode($this->response->raw_body);
129 |
130 | if ($body === null) {
131 | throw new Exception("Response body is invalid JSON.");
132 | }
133 |
134 | if ($asserted != $body) {
135 | $errorMessage = "Asserted body does not equal response body.";
136 | if ($onNotEqualVarExport) {
137 | $errorMessage .= "\n\n--------------- ASSERTED BODY ---------------\n" . var_export($asserted, true) .
138 | "\n\n--------------- RESPONSE BODY ---------------\n" . var_export($body, true) . "\n\n";
139 | }
140 | throw new Exception($errorMessage);
141 | }
142 |
143 | return $this;
144 | }
145 |
146 | public function assertBodyJsonFile($assertedJsonFile, $onNotEqualPrintJson = false)
147 | {
148 | if (!file_exists($assertedJsonFile)) {
149 | throw new Exception("Asserted JSON file '$assertedJsonFile' does not exist.");
150 | }
151 |
152 | $asserted = file_get_contents($assertedJsonFile);
153 | if (json_decode($asserted) === null) {
154 | throw new Exception("Asserted JSON file is invalid JSON.");
155 | }
156 |
157 | $body = $this->response->raw_body;
158 |
159 | if (json_decode($body) === null) {
160 | throw new Exception("Response body is invalid JSON.");
161 | }
162 |
163 | $asserted = prettyPrintJson($asserted);
164 | $body = prettyPrintJson($body);
165 |
166 | if ($asserted != $body) {
167 | $errorMessage = "Asserted JSON file does not equal response body.";
168 | if ($onNotEqualPrintJson) {
169 | $errorMessage .= "\n\n--------------- ASSERTED JSON FILE ---------------\n" . $asserted .
170 | "\n\n--------------- RESPONSE BODY ---------------\n" . $body . "\n\n";
171 | }
172 | throw new Exception($errorMessage);
173 | }
174 |
175 | return $this;
176 | }
177 |
178 | }
179 |
180 | function isAssoc($array)
181 | {
182 | return (bool) count(array_filter(array_keys($array), 'is_string'));
183 | }
184 |
185 | function prettyPrintJson($json)
186 | {
187 | $result = '';
188 | $level = 0;
189 | $prev_char = '';
190 | $in_quotes = false;
191 | $ends_line_level = null;
192 | $json_length = strlen($json);
193 |
194 | for ($i = 0; $i < $json_length; $i++) {
195 | $char = $json[$i];
196 | $new_line_level = null;
197 | $post = "";
198 | if ($ends_line_level !== null) {
199 | $new_line_level = $ends_line_level;
200 | $ends_line_level = null;
201 | }
202 | if ($char === '"' && $prev_char != '\\') {
203 | $in_quotes = !$in_quotes;
204 | } else {
205 | if (!$in_quotes) {
206 | switch ($char) {
207 | case '}':
208 | case ']':
209 | $level--;
210 | $ends_line_level = null;
211 | $new_line_level = $level;
212 | break;
213 |
214 | case '{':
215 | case '[':
216 | $level++;
217 | case ',':
218 | $ends_line_level = $level;
219 | break;
220 |
221 | case ':':
222 | $post = " ";
223 | break;
224 |
225 | case " ":
226 | case "\t":
227 | case "\n":
228 | case "\r":
229 | $char = "";
230 | $ends_line_level = $new_line_level;
231 | $new_line_level = null;
232 | break;
233 | }
234 | }
235 | }
236 | if ($new_line_level !== null) {
237 | $result .= "\n" . str_repeat("\t", $new_line_level);
238 | }
239 | $result .= $char . $post;
240 | $prev_char = $char;
241 | }
242 |
243 | return $result;
244 | }
--------------------------------------------------------------------------------
/tests/Ws/Http/ATest.php:
--------------------------------------------------------------------------------
1 | testAAA();
19 | // $this->testAuth();
20 | // $this->testGet();
21 | // $this->testPost();
22 | // $this->testJson();
23 | // $this->testJsonFile();
24 | }
25 |
26 | private function testAAA()
27 | {
28 | output(__METHOD__);
29 | try
30 | {
31 | $httpRequest = HttpRequest::create();
32 | $httpRequest->timeout(10);
33 | // $httpRequest->proxy('127.0.0.1','8888');
34 |
35 | $httpResponse = $httpRequest->get("http://117.121.26.105/admin/login",[
36 | 'User-Agent' => 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:47.0) Gecko/20100101 Firefox/47.0',
37 | ]);
38 |
39 | // $httpRequest->get("http://117.121.26.105/assets/application-e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855.css");
40 | // $httpRequest->get("http://117.121.26.105/assets/application-3be7df993ba49cb551697afa2cc2aa789f6b450516bdf1913f9d901b11cbb391.js");
41 | // $httpRequest->get("http://117.121.26.105/favicon.ico");
42 |
43 | output($httpResponse->headers);
44 | output($httpResponse->raw_body);
45 |
46 | $cookie = $httpResponse->headers['Set-Cookie'];
47 | $raw_body = $httpResponse->raw_body;
48 | // get token
49 | preg_match('', $raw_body, $tt);
50 |
51 | $authenticity_token = $tt[1];
52 |
53 | // $cookie = str_ireplace('%3D', '=', $cookie);
54 | // $cookie = str_ireplace('; path=/; HttpOnly', '', $cookie);
55 | $httpRequest->cookie($cookie);
56 | $body = [
57 | // 'utf8' => '✓',
58 | // 'authenticity_token' => $authenticity_token,
59 | 'login' => 'admin',
60 | 'password' => 'lottery',
61 | // '_method' => 'post',
62 | ];
63 | //
64 | $httpResponse = $httpRequest->post("http://117.121.26.105/admin/login",[
65 | 'Content-Type' => 'application/x-www-form-urlencoded',
66 | 'Host' => '117.121.26.105',
67 | 'Pragmal' => 'no-cache',
68 | 'Upgrade-Insecure-Requests' => 1,
69 | 'Cache-Control' => 'no-cache',
70 | 'Origin' => 'http://117.121.26.105',
71 | 'X-CSRF-Token' => $authenticity_token,
72 | 'User-Agent' => 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:47.0) Gecko/20100101 Firefox/47.0',
73 | 'Connection' => 'keep-alive',
74 | 'Accept' => 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
75 |
76 | 'X-Requested-With' => 'XMLHttpRequest',
77 | 'Referer' => 'http://117.121.26.105/admin/login',
78 | 'Accept-Encoding' => 'gzip, deflate',
79 | 'Accept-Language' => 'zh-CN,zh;q=0.8',
80 | // 'Cookie' => $cookie,
81 |
82 | ], $body);
83 |
84 |
85 | output($httpResponse->headers);
86 | output($httpResponse->raw_body);
87 |
88 | }
89 | catch(GlobalException $ex)
90 | {
91 | output( $ex->getMessage() , __METHOD__);
92 | }
93 |
94 | }
95 |
96 | private function testAuth()
97 | {
98 | output(__METHOD__);
99 | try
100 | {
101 | $httpRequest = HttpRequest::create();
102 | $httpRequest->auth("foo", "bar");
103 | $httpRequest->timeout(10);
104 |
105 | $httpResponse = $httpRequest->get("https://api.stripe.com");
106 | // output($httpResponse);
107 | $watcher = HttpWatcher::create($httpResponse);
108 |
109 | $watcher->assertStatusCode(401)
110 | ->assertHeadersExist(array(
111 | "Www-Authenticate"
112 | ))
113 | ->assertHeaders(array(
114 | "Server" => "nginx",
115 | "Cache-Control" => "no-cache, no-store"
116 | ))
117 | ->assertBody('IS_VALID_JSON');
118 | }
119 | catch(GlobalException $ex)
120 | {
121 | output( $ex->getMessage() , __METHOD__);
122 | }
123 | }
124 |
125 | private function testGet()
126 | {
127 | output(__METHOD__);
128 |
129 | $httpRequest = HttpRequest::create();
130 |
131 | try
132 | {
133 | output(__LINE__);
134 | $httpResponse = $httpRequest->get("https://freegeoip.net/csv/8.8.8.8");
135 | $watcher = HttpWatcher::create( $httpResponse );
136 |
137 | $watcher
138 | ->assertStatusCode(200)
139 | ->assertHeaders(array(
140 | "Access-Control-Allow-Origin" => "*"
141 | ))
142 | ->assertBody('"8.8.8.8","US","United States","","","","","38.0000","-97.0000","",""');
143 |
144 | }
145 | catch(GlobalException $ex)
146 | {
147 | output( $ex->getMessage() , __METHOD__ . ':freegeoip.net');
148 | }
149 |
150 | try
151 | {
152 | output(__LINE__);
153 | $httpResponse = $httpRequest->get("https://www.google.com");
154 | $watcher->setResponse( $httpResponse )
155 | ->assertStatusCode(200)
156 | ->assertHeadersExist(array(
157 | "X-Frame-Options"
158 | ))
159 | ->assertHeaders(array(
160 | "Server" => "gws",
161 | "Transfer-Encoding" => "chunked"
162 | ))
163 | ->assertBody("/.*/", true);
164 | }
165 | catch(GlobalException $ex)
166 | {
167 | output( $ex->getMessage() , __METHOD__ . ':google.com');
168 | }
169 |
170 | try
171 | {
172 | output(__LINE__);
173 | $httpResponse = $httpRequest->get("https://api.github.com");
174 | $watcher->setResponse( $httpResponse )
175 | ->assertStatusCode(200)
176 | ->assertHeadersExist(array(
177 | "X-GitHub-Request-Id",
178 | "ETag"
179 | ))
180 | ->assertHeaders(array(
181 | "Server" => "GitHub.com"
182 | ))
183 | ->assertBody('IS_VALID_JSON')
184 | ->assertTotalTimeLessThan(2);
185 | }
186 | catch(GlobalException $ex)
187 | {
188 | output( $ex->getMessage() , __METHOD__ . ':github.com');
189 | }
190 |
191 | // æµè¯ä»£çåè½,æ¬å°ä½¿ç¨Lantern (http://127.0.0.1:8787)
192 | try
193 | {
194 | output(__LINE__);
195 | $httpRequest->proxy('http://127.0.0.1', 8787);
196 |
197 | $httpResponse = $httpRequest->get("https://www.google.com");
198 | $watcher->setResponse( $httpResponse )
199 | ->assertStatusCode(200)
200 | ->assertHeadersExist(array(
201 | "X-Frame-Options"
202 | ))
203 | ->assertHeaders(array(
204 | "Server" => "gws",
205 | "Transfer-Encoding" => "chunked"
206 | ))
207 | ->assertBody("/.*/", true);
208 | }
209 | catch(GlobalException $ex)
210 | {
211 | output( $ex->getMessage() , __METHOD__ . ':google.com');
212 | }
213 |
214 | }
215 |
216 | private function testPost()
217 | {
218 | output(__METHOD__);
219 | try
220 | {
221 | $httpRequest = HttpRequest::create();
222 | $httpRequest->timeout(30);
223 | // æµè¯çååå¨å¢å¤ æ¬å°ä½¿ç¨Lantern (http://127.0.0.1:8787)
224 | $httpRequest->proxy('http://127.0.0.1', 8787);
225 |
226 | $httpResponse = $httpRequest->post("https://api.balancedpayments.com/api_keys");
227 | // output($httpResponse);
228 | $watcher = HttpWatcher::create($httpResponse);
229 |
230 | $watcher
231 | ->assertStatusCode(201)
232 | ->assertHeadersExist(array(
233 | "X-Balanced-Host",
234 | "X-Balanced-Guru"
235 | ))
236 | ->assertHeaders(array(
237 | "Content-Type" => "application/json"
238 | ))
239 | ->assertBody('IS_VALID_JSON');
240 | }
241 | catch(GlobalException $ex)
242 | {
243 | output( $ex->getMessage() , __METHOD__);
244 | }
245 | }
246 |
247 | private function testJson()
248 | {
249 | output(__METHOD__);
250 | try
251 | {
252 | $expected = new stdClass();
253 | $expected->ip = "8.8.8.8";
254 | $expected->country_code = "US";
255 | $expected->country_name = "United States";
256 | $expected->region_code = "CA";
257 | $expected->region_name = "California";
258 | $expected->city = "Mountain View";
259 | $expected->zip_code = "94040";
260 | $expected->time_zone = "America/Los_Angeles";
261 | $expected->latitude = 37.386000000000003;
262 | $expected->longitude = -122.0838;
263 | $expected->metro_code = 807;
264 |
265 | $httpRequest = HttpRequest::create();
266 |
267 | $httpResponse = $httpRequest->get("https://freegeoip.net/json/8.8.8.8");
268 | // output($httpResponse);
269 | $watcher = HttpWatcher::create($httpResponse);
270 |
271 | $watcher
272 | ->assertStatusCode(200)
273 | ->assertHeadersExist(array(
274 | "Date"
275 | ))
276 | ->assertHeaders(array(
277 | // "Access-Control-Allow-Origin" => "*"
278 | ))
279 | ->assertBodyJson($expected, true);
280 | }
281 | catch(GlobalException $ex)
282 | {
283 | output( $ex->getMessage() , __METHOD__);
284 | }
285 | }
286 |
287 | private function testJsonFile()
288 | {
289 | output(__METHOD__);
290 | try
291 | {
292 | $httpRequest = HttpRequest::create();
293 |
294 | $httpResponse = $httpRequest->get("https://freegeoip.net/json/8.8.8.8");
295 | // output($httpResponse);
296 | $watcher = HttpWatcher::create($httpResponse);
297 |
298 | $watcher
299 | ->assertStatusCode(200)
300 | ->assertHeadersExist(array(
301 | "Content-Length"
302 | ))
303 | ->assertHeaders(array(
304 | // "Access-Control-Allow-Origin" => "*"
305 | ))
306 | ->assertBodyJsonFile(__DIR__ . "/_json/freegeoip.net.json", true);
307 | }
308 | catch(GlobalException $ex)
309 | {
310 | output( $ex->getMessage() , __METHOD__);
311 | }
312 | }
313 |
314 | }
--------------------------------------------------------------------------------
/src/Ws/Http/ARequest.php:
--------------------------------------------------------------------------------
1 | jsonOpts($assoc, $depth, $options);
17 | }
18 |
19 | /**
20 | * Verify SSL peer
21 | *
22 | * @param bool $enabled enable SSL verification, by default is true
23 | * @return bool
24 | */
25 | public static function verifyPeer($enabled)
26 | {
27 | return Request::create('default')->verifyPeer($enabled);
28 | }
29 |
30 | /**
31 | * Verify SSL host
32 | *
33 | * @param bool $enabled enable SSL host verification, by default is true
34 | * @return bool
35 | */
36 | public static function verifyHost($enabled)
37 | {
38 | return Request::create('default')->verifyPeer($enabled);
39 | }
40 |
41 | /**
42 | * Verify SSL File
43 | *
44 | * @param string $file SSL verification file
45 | * @return string
46 | */
47 | public static function verifyFile($file)
48 | {
49 | return Request::create('default')->verifyFile($file);
50 | }
51 |
52 | /**
53 | * Get Verify SSL File
54 | *
55 | * @return string
56 | */
57 | public static function getVerifyFile()
58 | {
59 | return Request::create('default')->getVerifyFile();
60 | }
61 |
62 | /**
63 | * Set a timeout
64 | *
65 | * @param integer $seconds timeout value in seconds
66 | * @return integer
67 | */
68 | public static function timeout($seconds)
69 | {
70 | return Request::create('default')->timeout($seconds);
71 | }
72 |
73 | /**
74 | * Set a timeout
75 | *
76 | * @param integer $ms timeout value in millisecond
77 | * @return integer
78 | */
79 | public static function timeoutMs($ms)
80 | {
81 | return Request::create('default')->timeoutMs($ms);
82 | }
83 |
84 | /**
85 | * Set default headers to send on every request
86 | *
87 | * @param array $headers headers array
88 | * @return array
89 | */
90 | public static function defaultHeaders($headers)
91 | {
92 | return Request::create('default')->defaultHeaders($headers);
93 | }
94 |
95 | /**
96 | * Set a new default header to send on every request
97 | *
98 | * @param string $name header name
99 | * @param string $value header value
100 | * @return string
101 | */
102 | public static function defaultHeader($name, $value)
103 | {
104 | return Request::create('default')->defaultHeader($name, $value);
105 | }
106 |
107 | /**
108 | * Clear all the default headers
109 | */
110 | public static function clearDefaultHeaders()
111 | {
112 | return Request::create('default')->clearDefaultHeaders();
113 | }
114 |
115 | /**
116 | * Set curl options to send on every request
117 | *
118 | * @param array $options options array
119 | * @return array
120 | */
121 | public static function curlOpts($options)
122 | {
123 | return Request::create('default')->curlOpts($options);
124 | }
125 |
126 | /**
127 | * Set a new default header to send on every request
128 | *
129 | * @param string $name header name
130 | * @param string $value header value
131 | * @return string
132 | */
133 | public static function curlOpt($name, $value)
134 | {
135 | return Request::create('default')->curlOpt($name, $value);
136 | }
137 |
138 | /**
139 | * Clear all the default headers
140 | */
141 | public static function clearCurlOpts()
142 | {
143 | return Request::create('default')->clearCurlOpts();
144 | }
145 |
146 | /**
147 | * Set a cookie string for enabling cookie handling
148 | *
149 | * @param string $cookie
150 | */
151 | public static function cookie($cookie)
152 | {
153 | Request::create('default')->cookie($cookie);
154 | }
155 |
156 | /**
157 | * Set a cookie file path for enabling cookie handling
158 | *
159 | * $cookieFile must be a correct path with write permission
160 | *
161 | * @param string $cookieFile - path to file for saving cookie
162 | */
163 | public static function cookieFile($cookieFile)
164 | {
165 | Request::create('default')->cookieFile($cookieFile);
166 | }
167 |
168 | /**
169 | * Set authentication method to use
170 | *
171 | * @param string $username authentication username
172 | * @param string $password authentication password
173 | * @param integer $method authentication method
174 | */
175 | public static function auth($username = '', $password = '', $method = CURLAUTH_BASIC)
176 | {
177 | Request::create('default')->auth($username, $password, $method);
178 | }
179 |
180 | /**
181 | * Set proxy to use
182 | *
183 | * @param string $address proxy address
184 | * @param integer $port proxy port
185 | * @param integer $type (Available options for this are CURLPROXY_HTTP, CURLPROXY_HTTP_1_0 CURLPROXY_SOCKS4, CURLPROXY_SOCKS5, CURLPROXY_SOCKS4A and CURLPROXY_SOCKS5_HOSTNAME)
186 | * @param bool $tunnel enable/disable tunneling
187 | */
188 | public static function proxy($address, $port = 1080, $type = CURLPROXY_HTTP, $tunnel = false)
189 | {
190 | Request::create('default')->proxy($address, $port, $type, $tunnel);
191 | }
192 |
193 | /**
194 | * Set proxy authentication method to use
195 | *
196 | * @param string $username authentication username
197 | * @param string $password authentication password
198 | * @param integer $method authentication method
199 | */
200 | public static function proxyAuth($username = '', $password = '', $method = CURLAUTH_BASIC)
201 | {
202 | Request::create('default')->proxyAuth($username, $password, $method);
203 | }
204 |
205 | /**
206 | * Send a GET request to a URL
207 | *
208 | * @param string $url URL to send the GET request to
209 | * @param array $headers additional headers to send
210 | * @param mixed $parameters parameters to send in the querystring
211 | * @return \Ws\Http\Response
212 | */
213 | public static function get($url, $headers = [], $parameters = null)
214 | {
215 | return Request::create('default')->get($url, $headers, $parameters);
216 | }
217 |
218 | /**
219 | * Send a HEAD request to a URL
220 | * @param string $url URL to send the HEAD request to
221 | * @param array $headers additional headers to send
222 | * @param mixed $parameters parameters to send in the querystring
223 | * @return \Ws\Http\Response
224 | */
225 | public static function head($url, $headers = [], $parameters = null)
226 | {
227 | return Request::create('default')->head($url, $headers, $parameters);
228 | }
229 |
230 | /**
231 | * Send a OPTIONS request to a URL
232 | * @param string $url URL to send the OPTIONS request to
233 | * @param array $headers additional headers to send
234 | * @param mixed $parameters parameters to send in the querystring
235 | * @return \Ws\Http\Response
236 | */
237 | public static function options($url, $headers = [], $parameters = null)
238 | {
239 | return Request::create('default')->options($url, $headers, $parameters);
240 | }
241 |
242 | /**
243 | * Send a CONNECT request to a URL
244 | * @param string $url URL to send the CONNECT request to
245 | * @param array $headers additional headers to send
246 | * @param mixed $parameters parameters to send in the querystring
247 | * @return \Ws\Http\Response
248 | */
249 | public static function connect($url, $headers = [], $parameters = null)
250 | {
251 | return Request::create('default')->connect($url, $headers, $parameters);
252 | }
253 |
254 | /**
255 | * Send POST request to a URL
256 | * @param string $url URL to send the POST request to
257 | * @param array $headers additional headers to send
258 | * @param mixed $body POST body data
259 | * @return \Ws\Http\Response
260 | */
261 | public static function post($url, $headers = [], $body = null)
262 | {
263 | return Request::create('default')->post($url, $headers, $body);
264 | }
265 |
266 | /**
267 | * Send DELETE request to a URL
268 | * @param string $url URL to send the DELETE request to
269 | * @param array $headers additional headers to send
270 | * @param mixed $body DELETE body data
271 | * @return \Ws\Http\Response
272 | */
273 | public static function delete($url, $headers = [], $body = null)
274 | {
275 | return Request::create('default')->delete($url, $headers, $body);
276 | }
277 |
278 | /**
279 | * Send PUT request to a URL
280 | * @param string $url URL to send the PUT request to
281 | * @param array $headers additional headers to send
282 | * @param mixed $body PUT body data
283 | * @return \Ws\Http\Response
284 | */
285 | public static function put($url, $headers = [], $body = null)
286 | {
287 | return Request::create('default')->put($url, $headers, $body);
288 | }
289 |
290 | /**
291 | * Send PATCH request to a URL
292 | * @param string $url URL to send the PATCH request to
293 | * @param array $headers additional headers to send
294 | * @param mixed $body PATCH body data
295 | * @return \Ws\Http\Response
296 | */
297 | public static function patch($url, $headers = [], $body = null)
298 | {
299 | return Request::create('default')->patch($url, $headers, $body);
300 | }
301 |
302 | /**
303 | * Send TRACE request to a URL
304 | * @param string $url URL to send the TRACE request to
305 | * @param array $headers additional headers to send
306 | * @param mixed $body TRACE body data
307 | * @return \Ws\Http\Response
308 | */
309 | public static function trace($url, $headers = [], $body = null)
310 | {
311 | return Request::create('default')->trace($url, $headers, $body);
312 | }
313 |
314 | }
--------------------------------------------------------------------------------
/tests/Ws/Http/_json/a.automated.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "EtSAqRw4Sx5YFD3CYyq",
3 | "name": "夜点娱乐",
4 | "type": 1,
5 | "body": {
6 | "vars": [
7 | {
8 | "name": "token",
9 | "value": "1"
10 | },
11 | {
12 | "name": "openid",
13 | "value": ""
14 | },
15 | {
16 | "name": "userid",
17 | "value": "0"
18 | },
19 | {
20 | "name": "city",
21 | "value": "440100"
22 | },
23 | {
24 | "name": "searchKtvName",
25 | "value": "金柜"
26 | },
27 | {
28 | "name": "bookingKtvId",
29 | "value": ""
30 | },
31 | {
32 | "name": "bookingRoomtype",
33 | "value": ""
34 | },
35 | {
36 | "name": "bookingStart",
37 | "value": ""
38 | },
39 | {
40 | "name": "bookingEnd",
41 | "value": ""
42 | },
43 | {
44 | "name": "bookingDay",
45 | "value": ""
46 | },
47 | {
48 | "name": "loginCookie",
49 | "value": ""
50 | }
51 | ],
52 | "requests": [
53 | {
54 | "id": "1471348763956",
55 | "type": 1,
56 | "name": "微信用户登录token获取",
57 | "url": "http://production-yedian.chinacloudapp.cn/user/oauthlogin",
58 |
59 | "method": "POST",
60 | "timeout": "15 s",
61 | "header": {
62 | "X-KTV-Vendor-Name": "1d55af1659424cf94d869e2580a11bf8",
63 | "X-KTV-Application-Platform": "1",
64 | "X-KTV-Application-Name": "eec607d1f47c18c9160634fd0954da1a"
65 | },
66 | "authorization": {},
67 | "dataMode": "raw-json",
68 | "data": {
69 | "value": "{\"type\":\"wechat\",\"openid\":\"dddddddokwyOwsZZhu7_3zIQNtfB9r3CKhE\",\"display_name\":\"\\u7275\\u732a\\u7684\\u4ed3\\u9f20\",\"avatar_url\":\"http://wx.qlogo.cn/mmopen/JQpUg1oh5aelkvzXvcicURj0n4WzKJqBPr4RPjG6L9wyrKhGGKV1iaB4NJLod8Jn5y8ZCTCqIPED6l3av2iaEX3C88s1TaRLsA6/0\"}"
70 | },
71 | "postProcessors": [
72 | {
73 | "type": "setVar",
74 | "setVar": [
75 | {
76 | "match": "json",
77 | "attr": "token",
78 | "var": "token"
79 | },
80 | {
81 | "match": "header",
82 | "attr": "Set-Cookie",
83 | "var": "loginCookie"
84 | }
85 | ]
86 | },
87 | {
88 | "type": "asserts",
89 | "asserts": []
90 | }
91 | ]
92 | },
93 | {
94 | "id": "1471348763962",
95 | "type": 1,
96 | "name": "根据token获取用户信息",
97 | "url": "http://production-yedian.chinacloudapp.cn/user/info",
98 |
99 | "method": "GET",
100 | "timeout": "15s",
101 | "header": {
102 | "X-KTV-Vendor-Name": "1d55af1659424cf94d869e2580a11bf8",
103 | "X-KTV-Application-Platform": "1",
104 | "X-KTV-Application-Name": "eec607d1f47c18c9160634fd0954da1a",
105 | "X-KTV-User-Token": "$token"
106 | },
107 | "authorization": {},
108 | "dataMode": "params",
109 | "data": [],
110 | "postProcessors": [
111 | {
112 | "type": "setVar",
113 | "setVar": [
114 | {
115 | "match": "json",
116 | "attr": "openid",
117 | "var": "openid"
118 | },
119 | {
120 | "match": "json",
121 | "attr": "userid",
122 | "var": "userid"
123 | }
124 | ]
125 | },
126 | {
127 | "type": "asserts",
128 | "asserts": [
129 | {
130 | "match": "status",
131 | "attr": "",
132 | "method": "eq",
133 | "expect": "200"
134 | },
135 | {
136 | "match": "json",
137 | "attr": "result",
138 | "method": "eq",
139 | "expect": "0"
140 | }
141 | ]
142 | }
143 | ]
144 | },
145 | {
146 | "id": "1471354174497",
147 | "type": 1,
148 | "name": "按名称搜索KTV",
149 | "url": "http://production-yedian.chinacloudapp.cn/booking/xktvsearchlist",
150 |
151 | "method": "GET",
152 | "timeout": "15s",
153 | "header": {
154 | "X-KTV-Vendor-Name": "1d55af1659424cf94d869e2580a11bf8",
155 | "X-KTV-Application-Platform": "1",
156 | "X-KTV-Application-Name": "eec607d1f47c18c9160634fd0954da1a",
157 | "X-KTV-User-Token": "$token"
158 | },
159 | "authorization": {},
160 | "dataMode": "params",
161 | "data": [
162 | {"key": "offset", "value": "0", "type": "text"},
163 | {"key": "city", "value": "${city}", "type": "text"},
164 | {"key": "limit", "value": "27", "type": "text"},
165 | {"key": "name", "value": "${searchKtvName}", "type": "text"}
166 | ],
167 | "postProcessors": [
168 | {
169 | "type": "setVar",
170 | "setVar": [
171 | {
172 | "match": "json",
173 | "attr": "list[0].xktvid",
174 | "var": "bookingKtvId"
175 | }
176 | ]
177 | },
178 | {
179 | "type": "asserts",
180 | "asserts": [
181 | {
182 | "match": "status",
183 | "attr": "",
184 | "method": "eq",
185 | "expect": "200"
186 | },
187 | {
188 | "match": "json",
189 | "attr": "result",
190 | "method": "eq",
191 | "expect": "0"
192 | },
193 | {
194 | "match": "json",
195 | "attr": "total",
196 | "method": "gt",
197 | "expect": "0"
198 | }
199 | ]
200 | }
201 | ]
202 | },
203 | {
204 | "id": "1471356911011",
205 | "type": 1,
206 | "name": "选择具体门店",
207 | "url": "http://production-yedian.chinacloudapp.cn/booking/xktv",
208 |
209 | "method": "GET",
210 | "timeout": "15s",
211 | "header": {
212 | "X-KTV-Vendor-Name": "1d55af1659424cf94d869e2580a11bf8",
213 | "X-KTV-Application-Platform": "1",
214 | "X-KTV-Application-Name": "eec607d1f47c18c9160634fd0954da1a",
215 | "X-KTV-User-Token": "${token}"
216 | },
217 | "authorization": {},
218 | "dataMode": "params",
219 | "data": [
220 | {"key": "xktvid", "value": "${bookingKtvId}", "type": "text"}
221 | ],
222 | "postProcessors": [
223 | {
224 | "type": "setVar",
225 | "setVar": [
226 | {
227 | "match": "json",
228 | "attr": "data.taocaninfo.roomtype[0].id",
229 | "var": "bookingRoomtype"
230 | },
231 | {
232 | "match": "json",
233 | "attr": "data.taocaninfo.course[0].starttime.time",
234 | "var": "bookingStart"
235 | },
236 | {
237 | "match": "json",
238 | "attr": "data.taocaninfo.course[0].endtime.time",
239 | "var": "bookingEnd"
240 | },
241 | {
242 | "match": "json",
243 | "attr": "data.taocaninfo.days[0]",
244 | "var": "bookingDay"
245 | }
246 | ]
247 | },
248 | {
249 | "type": "asserts",
250 | "asserts": [
251 | {
252 | "match": "status",
253 | "attr": "",
254 | "method": "eq",
255 | "expect": "200"
256 | },
257 | {
258 | "match": "json",
259 | "attr": "result",
260 | "method": "eq",
261 | "expect": "0"
262 | },
263 | {
264 | "match": "json",
265 | "attr": "data",
266 | "method": "not_null",
267 | "expect": ""
268 | },
269 | {
270 | "match": "json",
271 | "attr": "data.xktvid",
272 | "method": "eq",
273 | "expect": "bookingKtvId"
274 | },
275 | {
276 | "match": "json",
277 | "attr": "data.taocaninfo",
278 | "method": "not_null",
279 | "expect": ""
280 | },
281 | {
282 | "match": "json",
283 | "attr": "data.taocaninfo.roomtype",
284 | "method": "not_null",
285 | "expect": ""
286 | }
287 | ]
288 | }
289 | ]
290 | },
291 | {
292 | "id": "1471358836839",
293 | "type": 1,
294 | "name": "提交订单",
295 | "url": "http://production-yedian.chinacloudapp.cn/booking/submitorder_new",
296 |
297 | "method": "POST",
298 | "timeout": "15s",
299 | "header": {
300 | "X-KTV-Vendor-Name": "1d55af1659424cf94d869e2580a11bf8",
301 | "X-KTV-Application-Platform": "1",
302 | "X-KTV-Application-Name": "eec607d1f47c18c9160634fd0954da1a",
303 | "cookie": "$loginCookie",
304 | "X-KTV-User-Token": "${token}"
305 | },
306 | "authorization": {},
307 | "dataMode": "raw-json",
308 | "data": {
309 | "value": "{\"ktvid\":\"${bookingKtvId}\",\"roomtype\":\"${bookingRoomtype}\",\"starttime\":\"${bookingDay} ${bookingStart}:00\",\"endtime\":\"${bookingDay} ${bookingEnd}:00\",\"couponid\":0,\"taocantype\":1,\"taocanid\":\"\",\"onlinepay\":0}"
310 | },
311 | "processors": [
312 | {
313 | "type": "setVar",
314 | "setVar": []
315 | },
316 | {
317 | "type": "asserts",
318 | "asserts": []
319 | }
320 | ]
321 | }
322 | ]
323 | }
324 | }
--------------------------------------------------------------------------------
/src/Ws/Http/Automated/example.json:
--------------------------------------------------------------------------------
1 | {
2 | "script_id": "EtSAqRw4Sx5YFD3CYyq",
3 | "script_name": "夜点娱乐",
4 | "trans": {
5 | "parameters": [
6 | {
7 | "name": "$token",
8 | "value": "1"
9 | },
10 | {
11 | "name": "$openid",
12 | "value": "''"
13 | },
14 | {
15 | "name": "$userid",
16 | "value": "0"
17 | },
18 | {
19 | "name": "$city",
20 | "value": "440100"
21 | },
22 | {
23 | "name": "$searchKtvName",
24 | "value": "金柜"
25 | },
26 | {
27 | "name": "$bookingKtvId",
28 | "value": "''"
29 | },
30 | {
31 | "name": "$bookingRoomtype",
32 | "value": "''"
33 | },
34 | {
35 | "name": "$bookingStart",
36 | "value": "''"
37 | },
38 | {
39 | "name": "$bookingEnd",
40 | "value": "''"
41 | },
42 | {
43 | "name": "$bookingDay",
44 | "value": "''"
45 | },
46 | {
47 | "name": "$loginCookie",
48 | "value": "''"
49 | }
50 | ],
51 | "steps": [
52 | {
53 | "actionId": "1471348763956",
54 | "type": 1,
55 | "actionName": "微信用户登录token获取",
56 | "url": "http://letsktv.chinacloudapp.cn/user/oauthlogin",
57 | "protocol": "http",
58 | "method": "POST",
59 | "header": {
60 | "X-KTV-Vendor-Name": "1d55af1659424cf94d869e2580a11bf8",
61 | "X-KTV-Application-Platform": "1",
62 | "X-KTV-Application-Name": "eec607d1f47c18c9160634fd0954da1a"
63 | },
64 | "authorization": {},
65 | "parameters": {},
66 | "formdata": {
67 | "type": "raw-text",
68 | "value": "{\"type\":\"wechat\",\"openid\":\"dddddddokwyOwsZZhu7_3zIQNtfB9r3CKhE\",\"display_name\":\"\\u7275\\u732a\\u7684\\u4ed3\\u9f20\",\"avatar_url\":\"http://wx.qlogo.cn/mmopen/JQpUg1oh5aelkvzXvcicURj0n4WzKJqBPr4RPjG6L9wyrKhGGKV1iaB4NJLod8Jn5y8ZCTCqIPED6l3av2iaEX3C88s1TaRLsA6/0\"}"
69 | },
70 | "postProcessors": [
71 | {
72 | "type": "propertyExtractor",
73 | "propertyExtractor": [
74 | {
75 | "matchBody": "json",
76 | "propertyName": "token",
77 | "goalProperty": "$token"
78 | },
79 | {
80 | "matchBody": "header",
81 | "propertyName": "Set-Cookie",
82 | "goalProperty": "$loginCookie"
83 | }
84 | ]
85 | },
86 | {
87 | "type": "assertions",
88 | "assertions": []
89 | }
90 | ]
91 | },
92 | {
93 | "actionId": "1471348763962",
94 | "type": 1,
95 | "actionName": "根据token获取用户信息",
96 | "url": "http://letsktv.chinacloudapp.cn/user/info",
97 | "protocol": "http",
98 | "method": "GET",
99 | "header": {
100 | "X-KTV-Vendor-Name": "1d55af1659424cf94d869e2580a11bf8",
101 | "X-KTV-Application-Platform": "1",
102 | "X-KTV-Application-Name": "eec607d1f47c18c9160634fd0954da1a",
103 | "X-KTV-User-Token": "$token"
104 | },
105 | "authorization": {},
106 | "parameters": {},
107 | "formdata": {},
108 | "postProcessors": [
109 | {
110 | "type": "propertyExtractor",
111 | "propertyExtractor": [
112 | {
113 | "matchBody": "json",
114 | "propertyName": "openid",
115 | "goalProperty": "$openid"
116 | },
117 | {
118 | "matchBody": "json",
119 | "propertyName": "userid",
120 | "goalProperty": "$userid"
121 | }
122 | ]
123 | },
124 | {
125 | "type": "assertions",
126 | "assertions": [
127 | {
128 | "matchBody": "status",
129 | "propertyName": "",
130 | "compareMethod": "eq",
131 | "expectedVal": "200"
132 | },
133 | {
134 | "matchBody": "json",
135 | "propertyName": "result",
136 | "compareMethod": "eq",
137 | "expectedVal": "0"
138 | }
139 | ]
140 | }
141 | ]
142 | },
143 | {
144 | "actionId": "1471354174497",
145 | "type": 1,
146 | "actionName": "按名称搜索KTV",
147 | "url": "http://letsktv.chinacloudapp.cn/booking/xktvsearchlist",
148 | "protocol": "http",
149 | "method": "GET",
150 | "header": {
151 | "X-KTV-Vendor-Name": "1d55af1659424cf94d869e2580a11bf8",
152 | "X-KTV-Application-Platform": "1",
153 | "X-KTV-Application-Name": "eec607d1f47c18c9160634fd0954da1a",
154 | "X-KTV-User-Token": "$token"
155 | },
156 | "authorization": {},
157 | "parameters": {
158 | "offset": "0",
159 | "city": "$city",
160 | "limit": "27",
161 | "name": "$searchKtvName"
162 | },
163 | "formdata": {},
164 | "postProcessors": [
165 | {
166 | "type": "propertyExtractor",
167 | "propertyExtractor": [
168 | {
169 | "matchBody": "json",
170 | "propertyName": "list[0].xktvid",
171 | "goalProperty": "$bookingKtvId"
172 | }
173 | ]
174 | },
175 | {
176 | "type": "assertions",
177 | "assertions": [
178 | {
179 | "matchBody": "status",
180 | "propertyName": "",
181 | "compareMethod": "eq",
182 | "expectedVal": "200"
183 | },
184 | {
185 | "matchBody": "json",
186 | "propertyName": "result",
187 | "compareMethod": "eq",
188 | "expectedVal": "0"
189 | },
190 | {
191 | "matchBody": "json",
192 | "propertyName": "total",
193 | "compareMethod": "gt",
194 | "expectedVal": "0"
195 | }
196 | ]
197 | }
198 | ]
199 | },
200 | {
201 | "actionId": "1471356911011",
202 | "type": 1,
203 | "actionName": "选择具体门店",
204 | "url": "http://letsktv.chinacloudapp.cn/booking/xktv",
205 | "protocol": "http",
206 | "method": "GET",
207 | "header": {
208 | "X-KTV-Vendor-Name": "1d55af1659424cf94d869e2580a11bf8",
209 | "X-KTV-Application-Platform": "1",
210 | "X-KTV-Application-Name": "eec607d1f47c18c9160634fd0954da1a",
211 | "X-KTV-User-Token": "$token"
212 | },
213 | "authorization": {},
214 | "parameters": {
215 | "xktvid": "$bookingKtvId"
216 | },
217 | "formdata": {},
218 | "postProcessors": [
219 | {
220 | "type": "propertyExtractor",
221 | "propertyExtractor": [
222 | {
223 | "matchBody": "json",
224 | "propertyName": "data.taocaninfo.roomtype[0].id",
225 | "goalProperty": "$bookingRoomtype"
226 | },
227 | {
228 | "matchBody": "json",
229 | "propertyName": "data.taocaninfo.course[0].starttime.time",
230 | "goalProperty": "$bookingStart"
231 | },
232 | {
233 | "matchBody": "json",
234 | "propertyName": "data.taocaninfo.course[0].endtime.time",
235 | "goalProperty": "$bookingEnd"
236 | },
237 | {
238 | "matchBody": "json",
239 | "propertyName": "data.taocaninfo.days[0]",
240 | "goalProperty": "$bookingDay"
241 | }
242 | ]
243 | },
244 | {
245 | "type": "assertions",
246 | "assertions": [
247 | {
248 | "matchBody": "status",
249 | "propertyName": "",
250 | "compareMethod": "eq",
251 | "expectedVal": "200"
252 | },
253 | {
254 | "matchBody": "json",
255 | "propertyName": "result",
256 | "compareMethod": "eq",
257 | "expectedVal": "0"
258 | },
259 | {
260 | "matchBody": "json",
261 | "propertyName": "data",
262 | "compareMethod": "not_null",
263 | "expectedVal": ""
264 | },
265 | {
266 | "matchBody": "json",
267 | "propertyName": "data.xktvid",
268 | "compareMethod": "eq",
269 | "expectedVal": "$bookingKtvId"
270 | },
271 | {
272 | "matchBody": "json",
273 | "propertyName": "data.taocaninfo",
274 | "compareMethod": "not_null",
275 | "expectedVal": ""
276 | },
277 | {
278 | "matchBody": "json",
279 | "propertyName": "data.taocaninfo.roomtype",
280 | "compareMethod": "not_null",
281 | "expectedVal": ""
282 | }
283 | ]
284 | }
285 | ]
286 | },
287 | {
288 | "actionId": "1471358836839",
289 | "type": 1,
290 | "actionName": "提交订单",
291 | "url": "http://letsktv.chinacloudapp.cn/booking/submitorder_new",
292 | "protocol": "http",
293 | "method": "POST",
294 | "header": {
295 | "X-KTV-Vendor-Name": "1d55af1659424cf94d869e2580a11bf8",
296 | "X-KTV-Application-Platform": "1",
297 | "X-KTV-Application-Name": "eec607d1f47c18c9160634fd0954da1a",
298 | "cookie": "$loginCookie",
299 | "X-KTV-User-Token": "$token"
300 | },
301 | "authorization": {},
302 | "parameters": {},
303 | "formdata": {
304 | "type": "raw-json",
305 | "value": "{\"ktvid\":\"$bookingKtvId\",\"roomtype\":\"$bookingRoomtype\",\"starttime\":\"$bookingDay $bookingStart:00\",\"endtime\":\"$bookingDay $bookingEnd:00\",\"couponid\":0,\"taocantype\":1,\"taocanid\":\"\",\"onlinepay\":0}"
306 | },
307 | "postProcessors": [
308 | {
309 | "type": "propertyExtractor",
310 | "propertyExtractor": []
311 | },
312 | {
313 | "type": "assertions",
314 | "assertions": []
315 | }
316 | ]
317 | }
318 | ]
319 | }
320 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ws-http
2 | ========
3 |
4 | #### 简单轻量的HTTP 客户端工具库(An Simplified, lightweight HTTP client library)
5 |
6 | 
7 |
8 | #### 可用于 HTTP API 测试,支持 ssl,basic auth,代理,自定义请求头,以及常用HTTP 请求方法.(An HTTP API testing framework, written in PHP using curl. Supports ssl, basic auth, passing custom request headers, and most HTTP request methods.
9 |
10 |
11 | ## 需求(Requirements)
12 |
13 | - [cURL](http://php.net/manual/en/book.curl.php)
14 | - PHP 5.4+
15 |
16 | ## 安装(Installation)
17 |
18 | ### 使用 (Using) [Composer](https://getcomposer.org)
19 |
20 | 在`composer.json`文件中新增如下行(To install ws-http with Composer, just add the following to your `composer.json` file):
21 |
22 | ```json
23 | {
24 | "require": {
25 | "toohamster/ws-http": "*"
26 | }
27 | }
28 | ```
29 |
30 | 或者手动运行命令(or by running the following command):
31 |
32 | ```shell
33 | php composer require toohamster/ws-http
34 | ```
35 |
36 | ## Http Request 使用(Http Request Usage)
37 |
38 | ### 创建一个请求(Creating a Request)
39 |
40 | ````php
41 | $httpRequest = \Ws\Http\Request::create();
42 | ````
43 |
44 | 支持的方法(Support Method)
45 | ---
46 |
47 | ````php
48 | // set config
49 | $httpRequest->jsonOpts($assoc = false, $depth = 512, $options = 0);
50 | $httpRequest->verifyPeer($enabled);
51 | $httpRequest->verifyHost($enabled);
52 | $httpRequest->verifyFile($file);
53 | $httpRequest->getVerifyFile();
54 | $httpRequest->timeout($seconds);
55 | $httpRequest->defaultHeaders($headers);
56 | $httpRequest->defaultHeader($name, $value);
57 | $httpRequest->clearDefaultHeaders();
58 | $httpRequest->curlOpts($options);
59 | $httpRequest->curlOpt($name, $value);
60 | $httpRequest->clearCurlOpts();
61 | $httpRequest->cookie($cookie);
62 | $httpRequest->cookieFile($cookieFile);
63 | $httpRequest->auth($username = '', $password = '', $method = CURLAUTH_BASIC);
64 | $httpRequest->proxy($address, $port = 1080, $type = CURLPROXY_HTTP, $tunnel = false);
65 | $httpRequest->proxyAuth($username = '', $password = '', $method = CURLAUTH_BASIC);
66 |
67 | // http call
68 | $httpRequest->get($url, $headers = [], $parameters = null);
69 | $httpRequest->head($url, $headers = [], $parameters = null);
70 | $httpRequest->options($url, $headers = [], $parameters = null);
71 | $httpRequest->connect($url, $headers = [], $parameters = null);
72 | $httpRequest->post($url, $headers = [], $body = null);
73 | $httpRequest->delete($url, $headers = [], $body = null);
74 | $httpRequest->put($url, $headers = [], $body = null);
75 | $httpRequest->patch($url, $headers = [], $body = null);
76 | $httpRequest->trace($url, $headers = [], $body = null);
77 | ````
78 |
79 | 此处给出一些简单的实例(Let's look at a working example):
80 |
81 | ```php
82 | $headers = array('Accept' => 'application/json');
83 | $query = array('foo' => 'hello', 'bar' => 'world');
84 |
85 | $response = $httpRequest->post('http://mockbin.com/request', $headers, $query);
86 |
87 | $response->code; // 请求响应码(HTTP Status code)
88 | $response->curl_info; // curl信息(HTTP Curl info)
89 | $response->headers; // 响应头(Headers)
90 | $response->body; // 处理后的响应消息体(Parsed body), 默认为 false
91 | $response->raw_body; // 原始响应消息体(Unparsed body)
92 | ```
93 |
94 | ### JSON 请求(Requests) *(`application/json`)*
95 |
96 | ```php
97 | $headers = array('Accept' => 'application/json');
98 | $data = array('name' => 'ahmad', 'company' => 'mashape');
99 |
100 | $body = Ws\Http\Request\Body::json($data);
101 |
102 | $response = $httpRequest->post('http://mockbin.com/request', $headers, $body);
103 | ```
104 |
105 | **注意(Notes):**
106 | - `Content-Type` 会自动设置成(headers will be automatically set to) `application/json`
107 |
108 | ### 表单请求(Form Requests) *(`application/x-www-form-urlencoded`)*
109 |
110 | ```php
111 | $headers = array('Accept' => 'application/json');
112 | $data = array('name' => 'ahmad', 'company' => 'mashape');
113 |
114 | $body = Ws\Http\Request\Body::form($data);
115 |
116 | $response = $httpRequest->post('http://mockbin.com/request', $headers, $body);
117 | ```
118 |
119 | **注意(Notes):**
120 | - `Content-Type` 会自动设置成(headers will be automatically set to) `application/x-www-form-urlencoded`
121 |
122 | ### Multipart Requests *(`multipart/form-data`)*
123 |
124 | ```php
125 | $headers = array('Accept' => 'application/json');
126 | $data = array('name' => 'ahmad', 'company' => 'mashape');
127 |
128 | $body = Ws\Http\Request\Body::multipart($data);
129 |
130 | $response = $httpRequest->post('http://mockbin.com/request', $headers, $body);
131 | ```
132 |
133 | **注意(Notes):**
134 |
135 | - `Content-Type` 会自动设置成(headers will be automatically set to) `multipart/form-data`.
136 |
137 | ### 文件上传(Multipart File Upload)
138 |
139 | ```php
140 | $headers = array('Accept' => 'application/json');
141 | $data = array('name' => 'ahmad', 'company' => 'mashape');
142 | $files = array('bio' => '/path/to/bio.txt', 'avatar' => '/path/to/avatar.jpg');
143 |
144 | $body = Ws\Http\Request\Body::multipart($data, $files);
145 |
146 | $response = $httpRequest->post('http://mockbin.com/request', $headers, $body);
147 | ```
148 |
149 | ```php
150 | $headers = array('Accept' => 'application/json');
151 | $body = array(
152 | 'name' => 'ahmad',
153 | 'company' => 'mashape'
154 | 'bio' => Ws\Http\Request\Body::file('/path/to/bio.txt', 'text/plain'),
155 | 'avatar' => Ws\Http\Request\Body::file('/path/to/my_avatar.jpg', 'text/plain', 'avatar.jpg')
156 | );
157 |
158 | $response = $httpRequest->post('http://mockbin.com/request', $headers, $body);
159 | ```
160 |
161 | ### 自定义消息体(Custom Body)
162 |
163 | 可以使用`Ws\Http\Request\Body`类提供的方法来生成消息体或使用PHP自带的序列化函数来生成消息体(Sending a custom body such rather than using the `Ws\Http\Request\Body` helpers is also possible, for example, using a [`serialize`](http://php.net/manual/en/function.serialize.php) body string with a custom `Content-Type`):
164 |
165 | ```php
166 | $headers = array('Accept' => 'application/json', 'Content-Type' => 'application/x-php-serialized');
167 | $body = serialize((array('foo' => 'hello', 'bar' => 'world'));
168 |
169 | $response = $httpRequest->post('http://mockbin.com/request', $headers, $body);
170 | ```
171 |
172 | ### 授权校验(Authentication)
173 |
174 | ```php
175 | $httpRequest->auth($username, $password, $method);// default is CURLAUTH_BASIC
176 | ```
177 |
178 | **支持的方法(Supported Methods)**
179 |
180 | | Method | Description |
181 | | -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
182 | | `CURLAUTH_BASIC` | HTTP Basic authentication. |
183 | | `CURLAUTH_DIGEST` | HTTP Digest authentication. as defined in [RFC 2617](http://www.ietf.org/rfc/rfc2617.txt) |
184 | | `CURLAUTH_DIGEST_IE` | HTTP Digest authentication with an IE flavor. *The IE flavor is simply that libcurl will use a special "quirk" that IE is known to have used before version 7 and that some servers require the client to use.* |
185 | | `CURLAUTH_NEGOTIATE` | HTTP Negotiate (SPNEGO) authentication. as defined in [RFC 4559](http://www.ietf.org/rfc/rfc4559.txt) |
186 | | `CURLAUTH_NTLM` | HTTP NTLM authentication. A proprietary protocol invented and used by Microsoft. |
187 | | `CURLAUTH_NTLM_WB` | NTLM delegating to winbind helper. Authentication is performed by a separate binary application. *see [libcurl docs](http://curl.haxx.se/libcurl/c/CURLOPT_HTTPAUTH.html) for more info* |
188 | | `CURLAUTH_ANY` | This is a convenience macro that sets all bits and thus makes libcurl pick any it finds suitable. libcurl will automatically select the one it finds most secure. |
189 | | `CURLAUTH_ANYSAFE` | This is a convenience macro that sets all bits except Basic and thus makes libcurl pick any it finds suitable. libcurl will automatically select the one it finds most secure. |
190 | | `CURLAUTH_ONLY` | This is a meta symbol. OR this value together with a single specific auth value to force libcurl to probe for un-restricted auth and if not, only that single auth algorithm is acceptable. |
191 |
192 | ```php
193 | // custom auth method
194 | $httpRequest->proxyAuth('username', 'password', CURLAUTH_DIGEST);
195 | ```
196 |
197 | ### Cookies
198 |
199 | ```php
200 | $httpRequest->cookie($cookie)
201 | ```
202 |
203 | ```php
204 | $httpRequest->cookieFile($cookieFile)
205 | ```
206 |
207 | `$cookieFile` 参数必须是可读取的文件路径(must be a correct path with write permission).
208 |
209 | ### 请求对象(Request Object)
210 |
211 | ```php
212 | $httpRequest->get($url, $headers = array(), $parameters = null)
213 | $httpRequest->post($url, $headers = array(), $body = null)
214 | $httpRequest->put($url, $headers = array(), $body = null)
215 | $httpRequest->patch($url, $headers = array(), $body = null)
216 | $httpRequest->delete($url, $headers = array(), $body = null)
217 | ```
218 |
219 | - `url` - 请求地址(Endpoint, address, or uri to be acted upon and requested information from)
220 | - `headers` - 请求头(Request Headers as associative array or object)
221 | - `body` - 请求消息体(Request Body as associative array or object)
222 |
223 | 可以使用标准的HTTP方法,也可以使用自定义的HTTP方法(You can send a request with any [standard](http://www.iana.org/assignments/http-methods/http-methods.xhtml) or custom HTTP Method):
224 |
225 | ```php
226 | $httpRequest->send(Ws\Http\Method::LINK, $url, $headers = array(), $body);
227 |
228 | $httpRequest->send('CHECKOUT', $url, $headers = array(), $body);
229 | ```
230 |
231 | ### 响应对象(Response Object)
232 |
233 | - `code` - 请求响应码(HTTP Status code)
234 | - `curl_info` - HTTP curl信息(HTTP Curl info)
235 | - `headers` - 响应头(HTTP Response Headers)
236 | - `body` - 处理后的响应消息体(Parsed body)
237 | - `raw_body` - 原始响应消息体(Unparsed body)
238 |
239 | ### 高级设置(Advanced Configuration)
240 |
241 | #### 自定义json_decode选项(Custom JSON Decode Flags)
242 |
243 | ```php
244 | $httpRequest->jsonOpts(true, 512, JSON_NUMERIC_CHECK & JSON_FORCE_OBJECT & JSON_UNESCAPED_SLASHES);
245 | ```
246 |
247 | #### 超时设置(Timeout)
248 |
249 | ```php
250 | $httpRequest->timeout(5); // 5s timeout
251 | ```
252 |
253 | #### 代理(Proxy)
254 |
255 | 可以设置代理类型(you can also set the proxy type to be one of) `CURLPROXY_HTTP`, `CURLPROXY_HTTP_1_0`, `CURLPROXY_SOCKS4`, `CURLPROXY_SOCKS5`, `CURLPROXY_SOCKS4A`, and `CURLPROXY_SOCKS5_HOSTNAME`.
256 |
257 | *check the [cURL docs](http://curl.haxx.se/libcurl/c/CURLOPT_PROXYTYPE.html) for more info*.
258 |
259 | ```php
260 | // quick setup with default port: 1080
261 | $httpRequest->proxy('10.10.10.1');
262 |
263 | // custom port and proxy type
264 | $httpRequest->proxy('10.10.10.1', 8080, CURLPROXY_HTTP);
265 |
266 | // enable tunneling
267 | $httpRequest->proxy('10.10.10.1', 8080, CURLPROXY_HTTP, true);
268 | ```
269 |
270 | ##### 代理授权验证 (Proxy Authenticaton)
271 |
272 | ```php
273 | // basic auth
274 | $httpRequest->proxyAuth('username', 'password', CURLAUTH_DIGEST);
275 | ```
276 |
277 | #### 缺省请求头 (Default Request Headers)
278 |
279 | ```php
280 | $httpRequest->defaultHeader('Header1', 'Value1');
281 | $httpRequest->defaultHeader('Header2', 'Value2');
282 | ```
283 |
284 | 批量配置(You can set default headers in bulk by passing an array):
285 |
286 | ```php
287 | $httpRequest->defaultHeaders(array(
288 | 'Header1' => 'Value1',
289 | 'Header2' => 'Value2'
290 | ));
291 | ```
292 |
293 | 清除配置(You can clear the default headers anytime with):
294 |
295 | ```php
296 | $httpRequest->clearDefaultHeaders();
297 | ```
298 |
299 | #### 缺省Curl选项 (Default cURL Options)
300 |
301 | You can set default [cURL options](http://php.net/manual/en/function.curl-setopt.php) that will be sent on every request:
302 |
303 | ```php
304 | $httpRequest->curlOpt(CURLOPT_COOKIE, 'foo=bar');
305 | ```
306 |
307 | 批量配置(You can set options bulk by passing an array):
308 |
309 | ```php
310 | $httpRequest->curlOpts(array(
311 | CURLOPT_COOKIE => 'foo=bar'
312 | ));
313 | ```
314 |
315 | 清除配置(You can clear the default options anytime with):
316 |
317 | ```php
318 | $httpRequest->clearCurlOpts();
319 | ```
320 |
321 | #### SSL validation
322 |
323 | ```php
324 | $httpRequest->verifyPeer(false); // Disables SSL cert validation
325 | ```
326 |
327 | By default is `true`.
328 |
329 |
330 | ## Http Watcher 使用(Http Watcher Usage)
331 |
332 | #### 支持的方法(Support Method)
333 |
334 | ````php
335 | $watcher = \Ws\Http\Watcher::create($httpResponse);
336 |
337 | $watcher->assertStatusCode($assertedStatusCode);
338 | $watcher->assertTotalTimeLessThan($assertedTime);
339 | $watcher->assertHeadersExist(array $assertedHeaders = []);
340 | $watcher->assertHeaders(array $assertedHeaders = []);
341 | $watcher->assertBody($assertedBody, $useRegularExpression = false);
342 | $watcher->assertBodyJson($asserted, $onNotEqualVarExport = false);
343 | $watcher->assertBodyJsonFile($assertedJsonFile, $onNotEqualPrintJson = false);
344 | ````
345 |
346 | ##### 例子(Examples)
347 |
348 | ````php
349 | $httpRequest = \Ws\Http\Request::create();
350 |
351 | $httpResponse = $httpRequest->get("https://api.github.com");
352 | $watcher = \Ws\Http\Watcher::create($httpResponse);
353 |
354 | $watcher
355 | ->assertStatusCode(200)
356 | ->assertHeadersExist(array(
357 | "X-GitHub-Request-Id",
358 | "ETag"
359 | ))
360 | ->assertHeaders(array(
361 | "Server" => "GitHub.com"
362 | ))
363 | ->assertBody('IS_VALID_JSON')
364 | ->assertTotalTimeLessThan(2);
365 | ````
366 |
367 | ````php
368 | $httpRequest = \Ws\Http\Request::create();
369 | $httpResponse = $httpRequest->get("https://freegeoip.net/json/8.8.8.8");
370 | $watcher = \Ws\Http\Watcher::create($httpResponse);
371 |
372 | $watcher
373 | ->assertStatusCode(200)
374 | ->assertHeadersExist(array(
375 | "Content-Length"
376 | ))
377 | ->assertHeaders(array(
378 | "Access-Control-Allow-Origin" => "*"
379 | ))
380 | ->assertBodyJsonFile(dirname(__DIR__) . "/tests/Ws/Http/_json/freegeoip.net.json");
381 | ````
382 |
383 | #### 查看所有例子(See the full examples) https://github.com/toohamster/ws-http/blob/master/tests/Ws/Http/ATest.php.
384 |
--------------------------------------------------------------------------------
/src/Ws/Http/Request.php:
--------------------------------------------------------------------------------
1 | '',
20 | 'pass' => '',
21 | 'method' => CURLAUTH_BASIC
22 | ];
23 |
24 | private $proxy = [
25 | 'port' => false,
26 | 'tunnel' => false,
27 | 'address' => false,
28 | 'type' => CURLPROXY_HTTP,
29 | 'auth' => [
30 | 'user' => '',
31 | 'pass' => '',
32 | 'method' => CURLAUTH_BASIC
33 | ]
34 | ];
35 |
36 | private function __construct()
37 | {
38 | $this->verifyFile = __DIR__ . '/_ssl/ca-bundle.crt';
39 | }
40 |
41 | /**
42 | * Get a Object
43 | *
44 | * @param string $id object identification, default auto build
45 | * @return \Ws\Http\Request
46 | */
47 | public static function create($id = null)
48 | {
49 | if ( empty($id) )
50 | {
51 | $id = md5(__METHOD__) . count(self::$instances);
52 | }
53 | if ( empty(self::$instances[$id]) )
54 | {
55 | self::$instances[$id] = new self();
56 | }
57 | return self::$instances[$id];
58 | }
59 |
60 | /**
61 | * Set JSON decode mode
62 | *
63 | * @param bool $assoc When TRUE, returned objects will be converted into associative arrays.
64 | * @param integer $depth User specified recursion depth.
65 | * @param integer $options Bitmask of JSON decode options. Currently only JSON_BIGINT_AS_STRING is supported (default is to cast large integers as floats)
66 | * @return array
67 | */
68 | public function jsonOpts($assoc = false, $depth = 512, $options = 0)
69 | {
70 | return $this->jsonOpts = [$assoc, $depth, $options];
71 | }
72 |
73 | /**
74 | * Verify SSL peer
75 | *
76 | * @param bool $enabled enable SSL verification, by default is true
77 | * @return bool
78 | */
79 | public function verifyPeer($enabled)
80 | {
81 | return $this->verifyPeer = $enabled;
82 | }
83 |
84 | /**
85 | * Verify SSL host
86 | *
87 | * @param bool $enabled enable SSL host verification, by default is true
88 | * @return bool
89 | */
90 | public function verifyHost($enabled)
91 | {
92 | return $this->verifyHost = $enabled;
93 | }
94 |
95 | /**
96 | * Verify SSL File
97 | *
98 | * @param string $file SSL verification file
99 | * @return string
100 | */
101 | public function verifyFile($file)
102 | {
103 | return $this->verifyFile = $file;
104 | }
105 |
106 | /**
107 | * Get Verify SSL File
108 | *
109 | * @return string
110 | */
111 | public function getVerifyFile()
112 | {
113 | return $this->verifyFile;
114 | }
115 |
116 | /**
117 | * Set a timeout
118 | *
119 | * @param integer $seconds timeout value in seconds
120 | * @return integer
121 | */
122 | public function timeout($seconds)
123 | {
124 | return $this->socketTimeout = $seconds;
125 | }
126 |
127 | /**
128 | * Set a timeout ms
129 | *
130 | * @param integer $ms timeout value in millisecond
131 | * @return integer
132 | */
133 | public function timeoutMs($ms)
134 | {
135 | return $this->socketTimeoutMs = $ms;
136 | }
137 |
138 | /**
139 | * Set default headers to send on every request
140 | *
141 | * @param array $headers headers array
142 | * @return array
143 | */
144 | public function defaultHeaders($headers)
145 | {
146 | return $this->defaultHeaders = array_merge($this->defaultHeaders, $headers);
147 | }
148 |
149 | /**
150 | * Set a new default header to send on every request
151 | *
152 | * @param string $name header name
153 | * @param string $value header value
154 | * @return string
155 | */
156 | public function defaultHeader($name, $value)
157 | {
158 | return $this->defaultHeaders[$name] = $value;
159 | }
160 |
161 | /**
162 | * Clear all the default headers
163 | */
164 | public function clearDefaultHeaders()
165 | {
166 | return $this->defaultHeaders = [];
167 | }
168 |
169 | /**
170 | * Set curl options to send on every request
171 | *
172 | * @param array $options options array
173 | * @return array
174 | */
175 | public function curlOpts($options)
176 | {
177 | return $this->mergeCurlOptions($this->curlOpts, $options);
178 | }
179 |
180 | /**
181 | * Set a new default header to send on every request
182 | *
183 | * @param string $name header name
184 | * @param string $value header value
185 | * @return string
186 | */
187 | public function curlOpt($name, $value)
188 | {
189 | return $this->curlOpts[$name] = $value;
190 | }
191 |
192 | /**
193 | * Clear all the default headers
194 | */
195 | public function clearCurlOpts()
196 | {
197 | return $this->curlOpts = [];
198 | }
199 |
200 | /**
201 | * Set a cookie string for enabling cookie handling
202 | *
203 | * @param string $cookie
204 | */
205 | public function cookie($cookie)
206 | {
207 | $this->cookie = $cookie;
208 | }
209 |
210 | /**
211 | * Set a cookie file path for enabling cookie handling
212 | *
213 | * $cookieFile must be a correct path with write permission
214 | *
215 | * @param string $cookieFile - path to file for saving cookie
216 | */
217 | public function cookieFile($cookieFile)
218 | {
219 | $this->cookieFile = $cookieFile;
220 | }
221 |
222 | /**
223 | * Set authentication method to use
224 | *
225 | * @param string $username authentication username
226 | * @param string $password authentication password
227 | * @param integer $method authentication method
228 | */
229 | public function auth($username = '', $password = '', $method = CURLAUTH_BASIC)
230 | {
231 | $this->auth['user'] = $username;
232 | $this->auth['pass'] = $password;
233 | $this->auth['method'] = $method;
234 | }
235 |
236 | /**
237 | * Set proxy to use
238 | *
239 | * @param string $address proxy address
240 | * @param integer $port proxy port
241 | * @param integer $type (Available options for this are CURLPROXY_HTTP, CURLPROXY_HTTP_1_0 CURLPROXY_SOCKS4, CURLPROXY_SOCKS5, CURLPROXY_SOCKS4A and CURLPROXY_SOCKS5_HOSTNAME)
242 | * @param bool $tunnel enable/disable tunneling
243 | */
244 | public function proxy($address, $port = 1080, $type = CURLPROXY_HTTP, $tunnel = false)
245 | {
246 | $this->proxy['type'] = $type;
247 | $this->proxy['port'] = $port;
248 | $this->proxy['tunnel'] = $tunnel;
249 | $this->proxy['address'] = $address;
250 | }
251 |
252 | /**
253 | * Set proxy authentication method to use
254 | *
255 | * @param string $username authentication username
256 | * @param string $password authentication password
257 | * @param integer $method authentication method
258 | */
259 | public function proxyAuth($username = '', $password = '', $method = CURLAUTH_BASIC)
260 | {
261 | $this->proxy['auth']['user'] = $username;
262 | $this->proxy['auth']['pass'] = $password;
263 | $this->proxy['auth']['method'] = $method;
264 | }
265 |
266 | /**
267 | * Send a GET request to a URL
268 | *
269 | * @param string $url URL to send the GET request to
270 | * @param array $headers additional headers to send
271 | * @param mixed $parameters parameters to send in the querystring
272 | * @return \Ws\Http\Response
273 | */
274 | public function get($url, $headers = [], $parameters = null)
275 | {
276 | return $this->send(Method::GET, $url, $parameters, $headers);
277 | }
278 |
279 | /**
280 | * Send a HEAD request to a URL
281 | * @param string $url URL to send the HEAD request to
282 | * @param array $headers additional headers to send
283 | * @param mixed $parameters parameters to send in the querystring
284 | * @return \Ws\Http\Response
285 | */
286 | public function head($url, $headers = [], $parameters = null)
287 | {
288 | return $this->send(Method::HEAD, $url, $parameters, $headers);
289 | }
290 |
291 | /**
292 | * Send a OPTIONS request to a URL
293 | * @param string $url URL to send the OPTIONS request to
294 | * @param array $headers additional headers to send
295 | * @param mixed $parameters parameters to send in the querystring
296 | * @return \Ws\Http\Response
297 | */
298 | public function options($url, $headers = [], $parameters = null)
299 | {
300 | return $this->send(Method::OPTIONS, $url, $parameters, $headers);
301 | }
302 |
303 | /**
304 | * Send a CONNECT request to a URL
305 | * @param string $url URL to send the CONNECT request to
306 | * @param array $headers additional headers to send
307 | * @param mixed $parameters parameters to send in the querystring
308 | * @return \Ws\Http\Response
309 | */
310 | public function connect($url, $headers = [], $parameters = null)
311 | {
312 | return $this->send(Method::CONNECT, $url, $parameters, $headers);
313 | }
314 |
315 | /**
316 | * Send POST request to a URL
317 | * @param string $url URL to send the POST request to
318 | * @param array $headers additional headers to send
319 | * @param mixed $body POST body data
320 | * @return \Ws\Http\Response
321 | */
322 | public function post($url, $headers = [], $body = null)
323 | {
324 | output(func_get_args(),'ppp');
325 | return $this->send(Method::POST, $url, $body, $headers);
326 | }
327 |
328 | /**
329 | * Send DELETE request to a URL
330 | * @param string $url URL to send the DELETE request to
331 | * @param array $headers additional headers to send
332 | * @param mixed $body DELETE body data
333 | * @return \Ws\Http\Response
334 | */
335 | public function delete($url, $headers = [], $body = null)
336 | {
337 | return $this->send(Method::DELETE, $url, $body, $headers);
338 | }
339 |
340 | /**
341 | * Send PUT request to a URL
342 | * @param string $url URL to send the PUT request to
343 | * @param array $headers additional headers to send
344 | * @param mixed $body PUT body data
345 | * @return \Ws\Http\Response
346 | */
347 | public function put($url, $headers = [], $body = null)
348 | {
349 | return $this->send(Method::PUT, $url, $body, $headers);
350 | }
351 |
352 | /**
353 | * Send PATCH request to a URL
354 | * @param string $url URL to send the PATCH request to
355 | * @param array $headers additional headers to send
356 | * @param mixed $body PATCH body data
357 | * @return \Ws\Http\Response
358 | */
359 | public function patch($url, $headers = [], $body = null)
360 | {
361 | return $this->send(Method::PATCH, $url, $body, $headers);
362 | }
363 |
364 | /**
365 | * Send TRACE request to a URL
366 | * @param string $url URL to send the TRACE request to
367 | * @param array $headers additional headers to send
368 | * @param mixed $body TRACE body data
369 | * @return \Ws\Http\Response
370 | */
371 | public function trace($url, $headers = [], $body = null)
372 | {
373 | return $this->send(Method::TRACE, $url, $body, $headers);
374 | }
375 |
376 | /**
377 | * This function is useful for serializing multidimensional arrays, and avoid getting
378 | * the 'Array to string conversion' notice
379 | * @param array|object $data array to flatten.
380 | * @param bool|string $parent parent key or false if no parent
381 | * @return array
382 | */
383 | public static function buildHTTPCurlQuery($data, $parent = false)
384 | {
385 | static $CFClassExist = null;
386 | if ( is_null($CFClassExist) )
387 | {
388 | $CFClassExist = class_exists('CURLFile', false);
389 | }
390 |
391 | $result = [];
392 |
393 | if (is_object($data)) {
394 | $data = get_object_vars($data);
395 | }
396 |
397 | foreach ($data as $key => $value) {
398 | if ($parent) {
399 | $new_key = sprintf('%s[%s]', $parent, $key);
400 | } else {
401 | $new_key = $key;
402 | }
403 |
404 | if ($CFClassExist && $value instanceof \CURLFile)
405 | {
406 | $result[$new_key] = $value;
407 | }
408 | else if (is_array($value) || is_object($value))
409 | {
410 | $result = array_merge($result, self::buildHTTPCurlQuery($value, $new_key));
411 | }
412 | else {
413 | $result[$new_key] = $value;
414 | }
415 | }
416 |
417 | return $result;
418 | }
419 |
420 | /**
421 | * Send a cURL request
422 | * @param string $method HTTP method to use
423 | * @param string $url URL to send the request to
424 | * @param mixed $body request body
425 | * @param array $headers additional headers to send
426 | * @throws \Ws\Http\Exception if a cURL error occurs
427 | * @return \Ws\Http\Response
428 | */
429 | public function send($method, $url, $body = null, $headers = [])
430 | {
431 | $handle = curl_init();
432 |
433 | if ($method !== Method::GET) {
434 | if ($method === Method::POST) {
435 | curl_setopt($handle, CURLOPT_POST, true);
436 | } else {
437 | curl_setopt($handle, CURLOPT_CUSTOMREQUEST, $method);
438 | }
439 |
440 | curl_setopt($handle, CURLOPT_POSTFIELDS, $body);
441 | } elseif (is_array($body)) {
442 | if (strpos($url, '?') !== false) {
443 | $url .= '&';
444 | } else {
445 | $url .= '?';
446 | }
447 |
448 | $url .= urldecode(http_build_query(self::buildHTTPCurlQuery($body)));
449 | }
450 |
451 | $curl_base_options = [
452 | CURLOPT_URL => self::encodeUrl($url),
453 | CURLOPT_RETURNTRANSFER => true,
454 | CURLOPT_FOLLOWLOCATION => true,
455 | CURLOPT_MAXREDIRS => 10,
456 | CURLOPT_HTTPHEADER => $this->getFormattedHeaders($headers),
457 | CURLOPT_HEADER => true,
458 | CURLOPT_SSL_VERIFYPEER => $this->verifyPeer,
459 | //CURLOPT_SSL_VERIFYHOST accepts only 0 (false) or 2 (true). Future versions of libcurl will treat values 1 and 2 as equals
460 | CURLOPT_SSL_VERIFYHOST => $this->verifyHost === false ? 0 : 2,
461 | // If an empty string, '', is set, a header containing all supported encoding types is sent
462 | CURLOPT_ENCODING => ''
463 | ];
464 |
465 | if ( $this->verifyPeer )
466 | {
467 | $curl_base_options[CURLOPT_CAINFO] = $this->getVerifyFile();
468 | }
469 |
470 | curl_setopt_array($handle, $this->mergeCurlOptions($curl_base_options, $this->curlOpts));
471 |
472 | if ($this->socketTimeout !== null) {
473 | curl_setopt($handle, CURLOPT_TIMEOUT, $this->socketTimeout);
474 | }
475 | else if ($this->socketTimeoutMs !== null) {
476 | if ( $this->socketTimeoutMs < 1000 )
477 | {
478 | // issue: http://www.laruence.com/2014/01/21/2939.html
479 | curl_setopt($handle, CURLOPT_NOSIGNAL, 1);
480 | }
481 | curl_setopt($handle, CURLOPT_TIMEOUT_MS, $this->socketTimeoutMs);
482 | }
483 |
484 | if ($this->cookie) {
485 | curl_setopt($handle, CURLOPT_COOKIE, $this->cookie);
486 | }
487 |
488 | if ($this->cookieFile) {
489 | curl_setopt($handle, CURLOPT_COOKIEFILE, $this->cookieFile);
490 | curl_setopt($handle, CURLOPT_COOKIEJAR, $this->cookieFile);
491 | }
492 |
493 | if (!empty($this->auth['user'])) {
494 | curl_setopt_array($handle, [
495 | CURLOPT_HTTPAUTH => $this->auth['method'],
496 | CURLOPT_USERPWD => $this->auth['user'] . ':' . $this->auth['pass']
497 | ]);
498 | }
499 |
500 | if ($this->proxy['address'] !== false) {
501 | curl_setopt_array($handle, [
502 | CURLOPT_PROXYTYPE => $this->proxy['type'],
503 | CURLOPT_PROXY => $this->proxy['address'],
504 | CURLOPT_PROXYPORT => $this->proxy['port'],
505 | CURLOPT_HTTPPROXYTUNNEL => $this->proxy['tunnel'],
506 | CURLOPT_PROXYAUTH => $this->proxy['auth']['method'],
507 | CURLOPT_PROXYUSERPWD => $this->proxy['auth']['user'] . ':' . $this->proxy['auth']['pass']
508 | ]);
509 | }
510 |
511 | $response = curl_exec($handle);
512 | $error = curl_error($handle);
513 | $info = curl_getinfo($handle);
514 |
515 | curl_close($handle);
516 |
517 | if ($error) {
518 | throw new Exception($error);
519 | }
520 |
521 | // Split the full response in its headers and body
522 | $header_size = $info['header_size'];
523 | $header = substr($response, 0, $header_size);
524 | $body = substr($response, $header_size);
525 |
526 | return new Response($info, $body, $header, $this->jsonOpts);
527 | }
528 |
529 | public function getFormattedHeaders($headers)
530 | {
531 | $formattedHeaders = [];
532 |
533 | $combinedHeaders = array_change_key_case(array_merge($this->defaultHeaders, (array) $headers));
534 |
535 | foreach ($combinedHeaders as $key => $val) {
536 | $formattedHeaders[] = $this->getHeaderString($key, $val);
537 | }
538 |
539 | if (!array_key_exists('user-agent', $combinedHeaders)) {
540 | $formattedHeaders[] = 'user-agent: ws-http/1.0';
541 | }
542 |
543 | if (!array_key_exists('expect', $combinedHeaders)) {
544 | $formattedHeaders[] = 'expect:';
545 | }
546 | return $formattedHeaders;
547 | }
548 |
549 | private static function getArrayFromQuerystring($query)
550 | {
551 | $query = preg_replace_callback('/(?:^|(?<=&))[^=[]+/', function ($match) {
552 | return bin2hex(urldecode($match[0]));
553 | }, $query);
554 |
555 | parse_str($query, $values);
556 |
557 | return array_combine(array_map('hex2bin', array_keys($values)), $values);
558 | }
559 |
560 | /**
561 | * Ensure that a URL is encoded and safe to use with cURL
562 | * @param string $url URL to encode
563 | * @return string
564 | */
565 | private static function encodeUrl($url)
566 | {
567 | $url_parsed = parse_url($url);
568 |
569 | $scheme = $url_parsed['scheme'] . '://';
570 | $host = $url_parsed['host'];
571 | $port = (isset($url_parsed['port']) ? $url_parsed['port'] : null);
572 | $path = (isset($url_parsed['path']) ? $url_parsed['path'] : null);
573 | $query = (isset($url_parsed['query']) ? $url_parsed['query'] : null);
574 |
575 | if ($query !== null) {
576 | $query = '?' . http_build_query(self::getArrayFromQuerystring($query));
577 | }
578 |
579 | if ($port && $port[0] !== ':') {
580 | $port = ':' . $port;
581 | }
582 |
583 | $result = $scheme . $host . $port . $path . $query;
584 | return $result;
585 | }
586 |
587 | private static function getHeaderString($key, $val)
588 | {
589 | $key = trim(strtolower($key));
590 | return $key . ': ' . $val;
591 | }
592 |
593 | /**
594 | * @param array $existing_options
595 | * @param array $new_options
596 | * @return array
597 | */
598 | private static function mergeCurlOptions(&$existing_options, $new_options)
599 | {
600 | $existing_options = $new_options + $existing_options;
601 | return $existing_options;
602 | }
603 | }
--------------------------------------------------------------------------------
/src/Ws/Http/Automated/postmanv1.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "f695cab7-6878-eb55-7943-ad88e1ccfd65",
3 | "name": "Postman Echo",
4 | "description": "Postman Echo is service you can use to test your REST clients and make sample API calls. It provides endpoints for `GET`, `POST`, `PUT`, various auth mechanisms and other utility endpoints.\n\nThe documentation for the endpoints as well as example responses can be found at [https://echo.getpostman.com](https://echo.getpostman.com?source=echo-collection-app-onboarding)",
5 | "order": [],
6 | "folders": [
7 | {
8 | "owner": 0,
9 | "lastUpdatedBy": "631643",
10 | "lastRevision": 277278520,
11 | "id": "09ddd67c-13fe-4626-8dd4-fc64f1fc27b7",
12 | "name": "Auth: Digest",
13 | "description": "Digest authentication protects an endpoint with a username and password without actually transmitting the password over network.\nOne has to apply a hash function (like MD5, etc) to the username and password before sending them over the network.\n\n> Username: `postman`\n>\n> Password: `password`\n\nUnlike Basic-Auth, authentication happens using two consecutive requests where the first request returns `401 Unauthorised` along with `WWW-Authenticate` header containing information that needs to be used to authenticate subsequent calls.\n\nTo know more about digest authentication, refer to the [Digest Access Authentication](https://en.wikipedia.org/wiki/Digest_access_authentication) wikipedia article.\nThe article on [authentication helpers](https://www.getpostman.com/docs/helpers#digest-auth) elaborates how to use the same within the Postman app.",
14 | "order": [
15 | "70ed7920-ead1-2d20-645a-c716ab0fd137",
16 | "a4c04e32-72cf-0475-07dc-89c23f85cf0c"
17 | ]
18 | },
19 | {
20 | "owner": 0,
21 | "lastUpdatedBy": "631643",
22 | "lastRevision": 277278516,
23 | "id": "df815c41-a76b-4b5b-7129-ea59275f254b",
24 | "name": "Auth: Others",
25 | "description": "",
26 | "order": [
27 | "42c867ca-e72b-3307-169b-26a478b00641",
28 | "2f79ab5b-9029-56c2-7b05-52047790d670",
29 | "843acf02-a33c-c4bb-d742-c07b9212e4b0"
30 | ]
31 | },
32 | {
33 | "owner": 0,
34 | "lastUpdatedBy": "631643",
35 | "lastRevision": 277278519,
36 | "id": "37368024-f6a8-0f70-85fc-7e876cde9e33",
37 | "name": "Cookies",
38 | "description": "The cookie related endpoints allow one to get, set and delete simple cookies.\n\nCookies are small snippets of information that is stored in the browser and sent back to the server with every subsequent requests in order to store useful information between requests.\nIf you want to know more about cookies, read the [HTTP Cookie](https://en.wikipedia.org/wiki/HTTP_cookie) article on wikipedia.",
39 | "order": [
40 | "3de3b135-b3cc-3a68-ba27-b6d373e03c8c",
41 | "a4f24593-448b-88de-963f-eeb952d38a57",
42 | "8dc08eee-a543-7c1c-297f-b0b7040c35c6"
43 | ]
44 | },
45 | {
46 | "owner": 0,
47 | "lastUpdatedBy": "631643",
48 | "lastRevision": 277278521,
49 | "id": "5d3595b3-5e8e-9e33-05ed-855c77298e4e",
50 | "name": "Headers",
51 | "description": "The following set of endpoints allow one to see the headers being sent as part of a request and to get a custom set of headers as part of response.\n\nHTTP header fields provide required information about the request or response, or about the object sent in the message body. Both request headers and response headers can be controlled using these endpoints.",
52 | "order": [
53 | "da16c006-6293-c1fe-ea42-e9ba8a5e68b1",
54 | "e50f9111-3a52-a325-47f1-fc702bea1fff"
55 | ]
56 | },
57 | {
58 | "owner": 0,
59 | "lastUpdatedBy": "631643",
60 | "lastRevision": 277278522,
61 | "id": "9a4c3bce-30f7-a496-c9ec-78afecbf1545",
62 | "name": "Request Methods",
63 | "description": "HTTP has multiple request \"verbs\", such as `GET`, `PUT`, `POST`, `DELETE`,\n`PATCH`, `HEAD`, etc. \n\nAn HTTP Method (verb) defines how a request should be interpreted by a server. \nThe endpoints in this section demonstrate various HTTP Verbs. Postman supports \nall the HTTP Verbs, including some rarely used ones, such as `PROPFIND`, `UNLINK`, \netc.\n\nFor details about HTTP Verbs, refer to [RFC 2616](http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9)\n",
64 | "order": [
65 | "078883ea-ac9e-842e-8f41-784b59a33722",
66 | "1eb1cf9d-2be7-4060-f554-73cd13940174",
67 | "12c51acc-50d2-2d9b-10d6-cc80e3a10d70",
68 | "8c53212f-42cd-cb37-6e02-08c47a7c8bb1",
69 | "1f0fad16-6bff-5130-2056-7f4af6b18912"
70 | ]
71 | },
72 | {
73 | "owner": 0,
74 | "lastUpdatedBy": "631643",
75 | "lastRevision": 277278518,
76 | "id": "930f54b4-c5cd-2363-7cf5-b9022d3c0aae",
77 | "name": "Utilities",
78 | "description": "",
79 | "order": [
80 | "6cfd22d8-26cc-7d3e-cf50-16d400211a76",
81 | "159a89e2-110d-0785-9dd7-9e73b2d6878b",
82 | "0189572f-509e-efe0-686d-eed4b3d2f1f0",
83 | "154510d1-65a8-a2d0-f157-aa2c694d7be7",
84 | "fd961ad0-ab24-68d8-4be5-573e8585d526",
85 | "5d3b31c0-fa26-ee03-5c1b-3715825d811d"
86 | ]
87 | }
88 | ],
89 | "timestamp": 0,
90 | "owner": 0,
91 | "public": false,
92 | "hasRequests": true,
93 | "requests": [
94 | {
95 | "folder": "930f54b4-c5cd-2363-7cf5-b9022d3c0aae",
96 | "id": "0189572f-509e-efe0-686d-eed4b3d2f1f0",
97 | "name": "Delay Response",
98 | "dataMode": "params",
99 | "data": [],
100 | "rawModeData": null,
101 | "descriptionFormat": null,
102 | "description": "Using this endpoint one can configure how long it takes for the server to come back with a response. Appending a number to the URL defines the time (in seconds) the server will wait before responding.\n\nNote that a maximum delay of 10 seconds is accepted by the server.",
103 | "headers": "",
104 | "method": "GET",
105 | "pathVariables": {},
106 | "url": "https://echo.getpostman.com/delay/3",
107 | "preRequestScript": "",
108 | "tests": "var responseJSON;\ntry { \n responseJSON = JSON.parse(responseBody); \n tests[\"response body has key delay\"] = 'delay' in responseJSON;\n}\ncatch (e) { }\ntests[\"response code is 200\"] = responseCode.code === 200;\n",
109 | "currentHelper": "normal",
110 | "helperAttributes": {},
111 | "collectionId": "f695cab7-6878-eb55-7943-ad88e1ccfd65",
112 | "responses": [
113 | {
114 | "owner": 0,
115 | "lastUpdatedBy": "631643",
116 | "lastRevision": 277278562,
117 | "request": {
118 | "url": "https://echo.getpostman.com/delay/1",
119 | "headers": [],
120 | "data": [],
121 | "method": "GET",
122 | "dataMode": "params"
123 | },
124 | "id": "c69827df-5275-773e-4753-7878a72fd156",
125 | "name": "sample delay response",
126 | "status": "",
127 | "responseCode": {
128 | "code": 200,
129 | "name": "OK"
130 | },
131 | "time": "1396",
132 | "headers": [
133 | {
134 | "name": "Access-Control-Allow-Credentials",
135 | "key": "Access-Control-Allow-Credentials",
136 | "value": "",
137 | "description": ""
138 | },
139 | {
140 | "name": "Access-Control-Allow-Headers",
141 | "key": "Access-Control-Allow-Headers",
142 | "value": "",
143 | "description": ""
144 | },
145 | {
146 | "name": "Access-Control-Allow-Methods",
147 | "key": "Access-Control-Allow-Methods",
148 | "value": "",
149 | "description": ""
150 | },
151 | {
152 | "name": "Access-Control-Allow-Origin",
153 | "key": "Access-Control-Allow-Origin",
154 | "value": "",
155 | "description": ""
156 | },
157 | {
158 | "name": "Connection",
159 | "key": "Connection",
160 | "value": "keep-alive",
161 | "description": ""
162 | },
163 | {
164 | "name": "Content-Length",
165 | "key": "Content-Length",
166 | "value": "13",
167 | "description": ""
168 | },
169 | {
170 | "name": "Content-Type",
171 | "key": "Content-Type",
172 | "value": "application/json; charset=utf-8",
173 | "description": ""
174 | },
175 | {
176 | "name": "Date",
177 | "key": "Date",
178 | "value": "Thu, 31 Mar 2016 12:00:02 GMT",
179 | "description": ""
180 | },
181 | {
182 | "name": "ETag",
183 | "key": "ETag",
184 | "value": "W/\"d-2835810952\"",
185 | "description": ""
186 | },
187 | {
188 | "name": "Server",
189 | "key": "Server",
190 | "value": "nginx/1.6.2",
191 | "description": ""
192 | },
193 | {
194 | "name": "Vary",
195 | "key": "Vary",
196 | "value": "Accept-Encoding",
197 | "description": ""
198 | },
199 | {
200 | "name": "X-Powered-By",
201 | "key": "X-Powered-By",
202 | "value": "Sails ",
203 | "description": ""
204 | }
205 | ],
206 | "cookies": [
207 | {
208 | "domain": ".getpostman.com",
209 | "expirationDate": 1460718898.059833,
210 | "hostOnly": false,
211 | "httpOnly": false,
212 | "name": "getpostmanlogin",
213 | "path": "/",
214 | "secure": false,
215 | "session": false,
216 | "storeId": "0",
217 | "value": "yes"
218 | },
219 | {
220 | "domain": ".getpostman.com",
221 | "expirationDate": 1460718898.059992,
222 | "hostOnly": false,
223 | "httpOnly": false,
224 | "name": "postman.sid",
225 | "path": "/",
226 | "secure": false,
227 | "session": false,
228 | "storeId": "0",
229 | "value": "df0c0256028d7ec4d641f766104a9571a8e249685bbc667d7cee030bbf44d3209495c70c03248e31e678a93812591d5e12187a8e99bf6bc5e80c40903f6ff6226938f24e413c0ffa613a7372064ec44a8594e8d3ede6945e34394f369573feeebc4a73a3e24b8c9ac18a53704addb5fd3f71f1ede488ff551feb059e9c1fb208164814e45e0312c4df8ea6e83c26702f42ae634c6afbe82d57c857bbf5598b5527961c1c28688dc2580070a4389f0cf4ec0a179b5b9c11b2ecbaa5460d374065bf5c7a3add9505df0fa89acb9f227f05ed2d4c6b58c39d6d728bd49f6f323ae67d4a75882aa7682f5d6fc5b981ba411d94aa93970bfaefa1953a73e440d50d012b5f288975c888e2345ee7777e746fb5aed3a7b2dbc087c6456621aa78c24a3c17c5f96cf59844933249a352f631e2008cffac6faf06d0e253dcc01cf0067bf56c1fbc5ed61fec1861b60c5accf35ffc2e56154a113004fa1db9d7171c3af8fc063918554092f5"
230 | },
231 | {
232 | "domain": ".echo.getpostman.com",
233 | "expirationDate": 1522494981,
234 | "hostOnly": false,
235 | "httpOnly": false,
236 | "name": "_ga",
237 | "path": "/",
238 | "secure": false,
239 | "session": false,
240 | "storeId": "0",
241 | "value": "GA1.3.1703443399.1459422978"
242 | },
243 | {
244 | "domain": "echo.getpostman.com",
245 | "hostOnly": true,
246 | "httpOnly": true,
247 | "name": "sails.sid",
248 | "path": "/",
249 | "secure": false,
250 | "session": true,
251 | "storeId": "0",
252 | "value": "s%3AE3eq7KE5S-hRJvtmRXXYRjTmlNz202zj.pbXR3%2F3TQ4g1827ALbVAcaxSQQjlzrZeHtLNFdbPD9c"
253 | }
254 | ],
255 | "mime": "",
256 | "text": "{\"delay\":\"1\"}",
257 | "language": "javascript",
258 | "rawDataType": "text",
259 | "state": {
260 | "size": "normal"
261 | },
262 | "previewType": "html",
263 | "searchResultScrolledTo": "-1",
264 | "version": null,
265 | "requestObject": "{\"url\":\"https://echo.getpostman.com/delay/1\",\"headers\":[],\"data\":[],\"method\":\"GET\",\"dataMode\":\"params\"}",
266 | "createdAt": "2016-05-25T12:29:57.000Z",
267 | "updatedAt": "2016-05-25T12:29:58.000Z",
268 | "write": true
269 | }
270 | ]
271 | },
272 | {
273 | "folder": "9a4c3bce-30f7-a496-c9ec-78afecbf1545",
274 | "id": "078883ea-ac9e-842e-8f41-784b59a33722",
275 | "name": "GET Request",
276 | "dataMode": "params",
277 | "data": [],
278 | "rawModeData": null,
279 | "descriptionFormat": null,
280 | "description": "The HTTP `GET` request method is meant to retrieve data from a server. The data\nis identified by a unique URI (Uniform Resource Identifier). \n\nA `GET` request can pass parameters to the server using \"Query String \nParameters\". For example, in the following request,\n\n> http://example.com/hi/there?hand=wave\n\nThe parameter \"hand\" has the value \"wave\".\n\nThis endpoint echoes the HTTP headers, request parameters and the complete\nURI requested.",
281 | "headers": "",
282 | "method": "GET",
283 | "pathVariables": {},
284 | "url": "https://echo.getpostman.com/get?test=123",
285 | "preRequestScript": "",
286 | "tests": "tests[\"Body contains headers\"] = responseBody.has(\"headers\");\ntests[\"Body contains args\"] = responseBody.has(\"args\");\ntests[\"Body contains url\"] = responseBody.has(\"url\");\n\nvar responseJSON;\n\ntry { responseJSON = JSON.parse(responseBody); }\ncatch (e) { }\n\n\ntests[\"Args key contains argument passed as url parameter\"] = 'test' in responseJSON.args",
287 | "currentHelper": "normal",
288 | "helperAttributes": {},
289 | "collectionId": "f695cab7-6878-eb55-7943-ad88e1ccfd65"
290 | },
291 | {
292 | "folder": "9a4c3bce-30f7-a496-c9ec-78afecbf1545",
293 | "id": "12c51acc-50d2-2d9b-10d6-cc80e3a10d70",
294 | "name": "PUT Request",
295 | "dataMode": "raw",
296 | "data": [],
297 | "descriptionFormat": null,
298 | "description": "The HTTP `PUT` request method is similar to HTTP `POST`. It too is meant to \ntransfer data to a server (and elicit a response). What data is returned depends on the implementation\nof the server.\n\nA `PUT` request can pass parameters to the server using \"Query String \nParameters\", as well as the Request Body. For example, in the following \nraw HTTP request,\n\n> PUT /hi/there?hand=wave\n>\n> \n\n\n",
299 | "headers": "",
300 | "method": "PUT",
301 | "pathVariables": {},
302 | "url": "https://echo.getpostman.com/put",
303 | "preRequestScript": "",
304 | "tests": "var data;\n\ntry { responseJSON = JSON.parse(responseBody); }\ncatch (e) {}\n\ntests[\"Body contains files\"] = responseBody.has(\"files\");\ntests[\"Body contains args\"] = responseBody.has(\"args\");\ntests[\"Body contains form\"] = responseBody.has(\"form\");\ntests[\"Body contains headers\"] = responseBody.has(\"headers\");\ntests[\"Body contains url\"] = responseBody.has(\"url\");\n\n\n\ntests[\"Data has been passed\"] = (responseJSON && responseJSON.data && responseJSON.data.length)",
305 | "currentHelper": "normal",
306 | "helperAttributes": {},
307 | "collectionId": "f695cab7-6878-eb55-7943-ad88e1ccfd65",
308 | "rawModeData": "Etiam mi lacus, cursus vitae felis et, blandit pellentesque neque. Vestibulum eget nisi a tortor commodo dignissim.\nQuisque ipsum ligula, faucibus a felis a, commodo elementum nisl. Mauris vulputate sapien et tincidunt viverra. Donec vitae velit nec metus."
309 | },
310 | {
311 | "folder": "930f54b4-c5cd-2363-7cf5-b9022d3c0aae",
312 | "id": "154510d1-65a8-a2d0-f157-aa2c694d7be7",
313 | "name": "Get UTF8 Encoded Response",
314 | "dataMode": "params",
315 | "data": [],
316 | "rawModeData": null,
317 | "descriptionFormat": null,
318 | "description": "If a response of an endpoint requires to send data beyond the basic English / ASCII character set, the `charset` parameter in the `Content-Type` response header defines the character encoding policy.\n\nThis endpoint returns an `UTF8` character encoded response body with text in various languages such as Greek, Latin, East Asian, etc. Postman can interpret the character encoding and use appropriate methods to display the character set in responses.",
319 | "headers": "",
320 | "method": "GET",
321 | "pathVariables": {},
322 | "url": "https://echo.getpostman.com/encoding/utf8",
323 | "preRequestScript": "",
324 | "tests": "tests[\"response code is 200\"] = responseCode.code === 200;",
325 | "currentHelper": "normal",
326 | "helperAttributes": {},
327 | "collectionId": "f695cab7-6878-eb55-7943-ad88e1ccfd65"
328 | },
329 | {
330 | "folder": "930f54b4-c5cd-2363-7cf5-b9022d3c0aae",
331 | "id": "159a89e2-110d-0785-9dd7-9e73b2d6878b",
332 | "name": "Streamed Response",
333 | "dataMode": "params",
334 | "data": [],
335 | "rawModeData": null,
336 | "descriptionFormat": null,
337 | "description": "This endpoint allows one to recieve streaming http response using [chunked transfer encoding](https://en.wikipedia.org/wiki/Chunked_transfer_encoding) of a configurable length.\n\nA streaming response does not wait for the entire response to be generated on server before flushing it out. This implies that for a fairly large response, parts of it can be streamed to the requestee as and when it is generated on server. The client can then take actions of processing this partially received data.",
338 | "headers": "",
339 | "method": "GET",
340 | "pathVariables": {},
341 | "url": "https://echo.getpostman.com/stream/10",
342 | "preRequestScript": "",
343 | "tests": "tests[\"response code is 200\"] = responseCode.code === 200;\ntests[\"response is sent in chunks\"] = (postman.getResponseHeader('Transfer-Encoding') === 'chunked')\n",
344 | "currentHelper": "normal",
345 | "helperAttributes": {},
346 | "collectionId": "f695cab7-6878-eb55-7943-ad88e1ccfd65"
347 | },
348 | {
349 | "folder": "9a4c3bce-30f7-a496-c9ec-78afecbf1545",
350 | "id": "1eb1cf9d-2be7-4060-f554-73cd13940174",
351 | "name": "POST Request",
352 | "dataMode": "raw",
353 | "data": [],
354 | "descriptionFormat": null,
355 | "description": "The HTTP `POST` request method is meant to transfer data to a server \n(and elicit a response). What data is returned depends on the implementation\nof the server.\n\nA `POST` request can pass parameters to the server using \"Query String \nParameters\", as well as the Request Body. For example, in the following request,\n\n> POST /hi/there?hand=wave\n>\n> \n\nThe parameter \"hand\" has the value \"wave\". The request body can be in multiple\nformats. These formats are defined by the MIME type of the request. The MIME \nType can be set using the ``Content-Type`` HTTP header. The most commonly used \nMIME types are:\n\n* `multipart/form-data`\n* `application/x-www-form-urlencoded`\n* `application/json`\n\nThis endpoint echoes the HTTP headers, request parameters, the contents of\nthe request body and the complete URI requested.",
356 | "headers": "Content-Type: text/plain\n",
357 | "method": "POST",
358 | "pathVariables": {},
359 | "url": "https://echo.getpostman.com/post",
360 | "preRequestScript": "",
361 | "tests": "var responseJSON;\n\ntry { responseJSON = JSON.parse(responseBody); }\ncatch (e) { }\n\n\ntests[\"response has data\"] = responseJSON && responseJSON.data && (responseJSON.data.length === 256);\ntests[\"content-type equals text/plain\"] = responseJSON && responseJSON.headers && (responseJSON.headers[\"content-type\"] === 'text/plain');",
362 | "currentHelper": "normal",
363 | "helperAttributes": {},
364 | "collectionId": "f695cab7-6878-eb55-7943-ad88e1ccfd65",
365 | "rawModeData": "Duis posuere augue vel cursus pharetra. In luctus a ex nec pretium. Praesent neque quam, tincidunt nec leo eget, rutrum vehicula magna.\nMaecenas consequat elementum elit, id semper sem tristique et. Integer pulvinar enim quis consectetur interdum volutpat."
366 | },
367 | {
368 | "folder": "9a4c3bce-30f7-a496-c9ec-78afecbf1545",
369 | "id": "1f0fad16-6bff-5130-2056-7f4af6b18912",
370 | "name": "DELETE Request",
371 | "dataMode": "raw",
372 | "data": [],
373 | "descriptionFormat": null,
374 | "description": "The HTTP `DELETE` method is used to delete resources on a server. The exact\nuse of `DELETE` requests depends on the server implementation. In general, \n`DELETE` requests support both, Query String parameters as well as a Request \nBody.\n\nThis endpoint accepts an HTTP `DELETE` request and provides debug information\nsuch as the HTTP headers, Query String arguments, and the Request Body.",
375 | "headers": "",
376 | "method": "DELETE",
377 | "pathVariables": {},
378 | "url": "https://echo.getpostman.com/delete",
379 | "preRequestScript": "",
380 | "tests": "tests[\"Body contains files\"] = responseBody.has(\"files\");\ntests[\"Body contains args\"] = responseBody.has(\"args\");\ntests[\"Body contains form\"] = responseBody.has(\"form\");\ntests[\"Body contains headers\"] = responseBody.has(\"headers\");\ntests[\"Body contains url\"] = responseBody.has(\"url\");\n\nvar responseJSON;\n\ntry { responseJSON = JSON.parse(responseBody); }\ncatch (e) { }\n\ntests[\"Data has been passed\"] = (responseJSON && responseJSON.data && responseJSON.data.length)",
381 | "currentHelper": "normal",
382 | "helperAttributes": {},
383 | "collectionId": "f695cab7-6878-eb55-7943-ad88e1ccfd65",
384 | "rawModeData": "Donec fermentum, nisi sed cursus eleifend, nulla tortor ultricies tellus, ut vehicula orci arcu ut velit. In volutpat egestas dapibus. \nMorbi condimentum vestibulum sapien. Etiam dignissim diam quis eros lobortis gravida vel lobortis est. Etiam gravida sed."
385 | },
386 | {
387 | "folder": "df815c41-a76b-4b5b-7129-ea59275f254b",
388 | "id": "2f79ab5b-9029-56c2-7b05-52047790d670",
389 | "name": "OAuth1.0 Verify Signature",
390 | "dataMode": "params",
391 | "data": [
392 | {
393 | "key": "code",
394 | "value": "xWnkliVQJURqB2x1",
395 | "type": "text",
396 | "enabled": true
397 | },
398 | {
399 | "key": "grant_type",
400 | "value": "authorization_code",
401 | "type": "text",
402 | "enabled": true
403 | },
404 | {
405 | "key": "redirect_uri",
406 | "value": "https://www.getpostman.com/oauth2/callback",
407 | "type": "text",
408 | "enabled": true
409 | },
410 | {
411 | "key": "client_id",
412 | "value": "abc123",
413 | "type": "text",
414 | "enabled": true
415 | },
416 | {
417 | "key": "client_secret",
418 | "value": "ssh-secret",
419 | "type": "text",
420 | "enabled": true
421 | }
422 | ],
423 | "rawModeData": null,
424 | "descriptionFormat": null,
425 | "description": "OAuth1.0a is a specification that defines a protocol that can be used by one\nservice to access \"protected\" resources (endpoints) on another service. A\nmajor part of OAuth1.0 is HTTP Request Signing. This endpoint allows you to \ncheck whether the request calculation works properly in the client. \n\nThe endpoint supports the HTTP ``Authorization`` header. In case the signature\nverification fails, the endpoint provides the four debug values,\n\n* ``base_uri``\n* ``normalized_param_string``\n* ``base_string``\n* ``signing_key``\n\nFor more details about these parameters, check the [OAuth1.0a Specification](http://oauth.net/core/1.0a/)\n\nIn order to use this endpoint, you can set the following values:\n\n> Consumer Key: ``RKCGzna7bv9YD57c``\n>\n> Consumer Secret: ``D+EdQ-gs$-%@2Nu7``\n\nIf you are using Postman, also check the \"Add params to header\" and \n\"Auto add parameters\" boxes.",
426 | "headers": "Authorization: OAuth oauth_consumer_key=\"RKCGzna7bv9YD57c\",oauth_signature_method=\"HMAC-SHA1\",oauth_timestamp=\"1442394747\",oauth_nonce=\"UIGipk\",oauth_version=\"1.0\",oauth_signature=\"CaeyGPr2mns1WCq4Cpm5aLvz6Gs=\"\n",
427 | "method": "GET",
428 | "pathVariables": {},
429 | "url": "https://echo.getpostman.com/oauth1",
430 | "preRequestScript": "",
431 | "tests": "tests[\"response code is 200\"] = responseCode.code === 200;\nvar body = JSON.parse(responseBody);\ntests[\"Body contains status pass\"] = body[\"status\"] == \"pass\"",
432 | "currentHelper": "normal",
433 | "helperAttributes": {},
434 | "collectionId": "f695cab7-6878-eb55-7943-ad88e1ccfd65",
435 | "responses": [
436 | {
437 | "owner": 0,
438 | "lastUpdatedBy": "631643",
439 | "lastRevision": 277278569,
440 | "request": {
441 | "url": "https://echo.getpostman.com/oauth1",
442 | "headers": [
443 | {
444 | "key": "Authorization",
445 | "value": "OAuth oauth_consumer_key=\"RKCGzna7bv9YD57c\",oauth_signature_method=\"HMAC-SHA1\",oauth_timestamp=\"1442394747\",oauth_nonce=\"UIGipk\",oauth_version=\"1.0\",oauth_signature=\"CaeyGPr2mns1WCq4Cpm5aLvz6Gs=\"",
446 | "enabled": true
447 | }
448 | ],
449 | "data": [
450 | {
451 | "key": "code",
452 | "value": "xWnkliVQJURqB2x1",
453 | "type": "text",
454 | "enabled": true
455 | },
456 | {
457 | "key": "grant_type",
458 | "value": "authorization_code",
459 | "type": "text",
460 | "enabled": true
461 | },
462 | {
463 | "key": "redirect_uri",
464 | "value": "https://www.getpostman.com/oauth2/callback",
465 | "type": "text",
466 | "enabled": true
467 | },
468 | {
469 | "key": "client_id",
470 | "value": "abc123",
471 | "type": "text",
472 | "enabled": true
473 | },
474 | {
475 | "key": "client_secret",
476 | "value": "ssh-secret",
477 | "type": "text",
478 | "enabled": true
479 | }
480 | ],
481 | "method": "GET",
482 | "dataMode": "params"
483 | },
484 | "id": "e504bab6-3d35-fe24-1c4e-c36f5b7b269e",
485 | "name": "Success",
486 | "status": "",
487 | "responseCode": {
488 | "code": 200,
489 | "name": "OK"
490 | },
491 | "time": "4663",
492 | "headers": [
493 | {
494 | "name": "Access-Control-Allow-Credentials",
495 | "key": "Access-Control-Allow-Credentials",
496 | "value": "",
497 | "description": ""
498 | },
499 | {
500 | "name": "Access-Control-Allow-Headers",
501 | "key": "Access-Control-Allow-Headers",
502 | "value": "",
503 | "description": ""
504 | },
505 | {
506 | "name": "Access-Control-Allow-Methods",
507 | "key": "Access-Control-Allow-Methods",
508 | "value": "",
509 | "description": ""
510 | },
511 | {
512 | "name": "Access-Control-Allow-Origin",
513 | "key": "Access-Control-Allow-Origin",
514 | "value": "",
515 | "description": ""
516 | },
517 | {
518 | "name": "Connection",
519 | "key": "Connection",
520 | "value": "keep-alive",
521 | "description": ""
522 | },
523 | {
524 | "name": "Content-Encoding",
525 | "key": "Content-Encoding",
526 | "value": "gzip",
527 | "description": ""
528 | },
529 | {
530 | "name": "Content-Length",
531 | "key": "Content-Length",
532 | "value": "95",
533 | "description": ""
534 | },
535 | {
536 | "name": "Content-Type",
537 | "key": "Content-Type",
538 | "value": "application/json; charset=utf-8",
539 | "description": ""
540 | },
541 | {
542 | "name": "Date",
543 | "key": "Date",
544 | "value": "Thu, 31 Mar 2016 11:06:58 GMT",
545 | "description": ""
546 | },
547 | {
548 | "name": "Server",
549 | "key": "Server",
550 | "value": "nginx/1.6.2",
551 | "description": ""
552 | },
553 | {
554 | "name": "Vary",
555 | "key": "Vary",
556 | "value": "Accept-Encoding",
557 | "description": ""
558 | },
559 | {
560 | "name": "X-Powered-By",
561 | "key": "X-Powered-By",
562 | "value": "Sails ",
563 | "description": ""
564 | }
565 | ],
566 | "cookies": [
567 | {
568 | "domain": "echo.getpostman.com",
569 | "hostOnly": true,
570 | "httpOnly": true,
571 | "name": "sails.sid",
572 | "path": "/",
573 | "secure": false,
574 | "session": true,
575 | "storeId": "0",
576 | "value": "s%3ABp7Ij29KkCZa6ZDcop8c91ouBjNzAbD0.ejn6dE%2FhqlpsDh7QUsPXPozN7UBdAzW4i15PEFhHbZg"
577 | },
578 | {
579 | "domain": ".getpostman.com",
580 | "expirationDate": 1460717668.06945,
581 | "hostOnly": false,
582 | "httpOnly": false,
583 | "name": "getpostmanlogin",
584 | "path": "/",
585 | "secure": false,
586 | "session": false,
587 | "storeId": "0",
588 | "value": "yes"
589 | },
590 | {
591 | "domain": ".getpostman.com",
592 | "expirationDate": 1460717668.069509,
593 | "hostOnly": false,
594 | "httpOnly": false,
595 | "name": "postman.sid",
596 | "path": "/",
597 | "secure": false,
598 | "session": false,
599 | "storeId": "0",
600 | "value": "9f887f3b7f14b8c29ac4dc4109381b0b89a76e785c7b34251d6c8025b41b24013d2aa49f40e2deac19cbf0594dd984169455534d91ff98d4d1868d67ac857017629f137926e3a04a616bb83a2fb5ab9e6cbea9579ed5d5c1155d47545d72aad5be99f4abd0a7130805b3807d70cd507171dbe9d950d8e35a853f9ec075f5a767c95df4d57f7d521b66605b3bda3801700e26e651d1129c798b729ee3b91702d43ae64ab226c3f426893753def772c15442a7552dc84a3c773d6099a50b0a6af940b64c8176fedfcecd5fc31ccfc3bbc0124bfdaa0d62e4252d4aafb46a3c10963d12391e1fa97a1c0f19a636f57a3ac8cc35567d1cb6cb53b77f8adde3f6754a765596d7d00bdeb9acb5cc8d115e7c3f50ec3228e34d3e6c7464e9039b01868e03d10e9f87772397602453e9e91205de7b86021fad06eb26e69298e99ff1597a670faeb310f8c092041d544851de84f2bee89a92123da6eea286210524035c85361e2af42166a6"
601 | }
602 | ],
603 | "mime": "",
604 | "text": "{\"status\":\"pass\",\"message\":\"OAuth-1.0a signature verification was successful\"}",
605 | "language": "javascript",
606 | "rawDataType": "text",
607 | "state": {
608 | "size": "normal"
609 | },
610 | "previewType": "html",
611 | "searchResultScrolledTo": "-1",
612 | "version": null,
613 | "requestObject": "{\"url\":\"https://echo.getpostman.com/oauth1\",\"headers\":[{\"key\":\"Authorization\",\"value\":\"OAuth oauth_consumer_key=\\\"RKCGzna7bv9YD57c\\\",oauth_signature_method=\\\"HMAC-SHA1\\\",oauth_timestamp=\\\"1442394747\\\",oauth_nonce=\\\"UIGipk\\\",oauth_version=\\\"1.0\\\",oauth_signature=\\\"CaeyGPr2mns1WCq4Cpm5aLvz6Gs=\\\"\",\"enabled\":true}],\"data\":[{\"key\":\"code\",\"value\":\"xWnkliVQJURqB2x1\",\"type\":\"text\",\"enabled\":true},{\"key\":\"grant_type\",\"value\":\"authorization_code\",\"type\":\"text\",\"enabled\":true},{\"key\":\"redirect_uri\",\"value\":\"https://www.getpostman.com/oauth2/callback\",\"type\":\"text\",\"enabled\":true},{\"key\":\"client_id\",\"value\":\"abc123\",\"type\":\"text\",\"enabled\":true},{\"key\":\"client_secret\",\"value\":\"ssh-secret\",\"type\":\"text\",\"enabled\":true}],\"method\":\"GET\",\"dataMode\":\"params\"}",
614 | "createdAt": "2016-05-25T12:29:58.000Z",
615 | "updatedAt": "2016-05-25T12:29:58.000Z",
616 | "write": true
617 | }
618 | ]
619 | },
620 | {
621 | "folder": "37368024-f6a8-0f70-85fc-7e876cde9e33",
622 | "id": "3de3b135-b3cc-3a68-ba27-b6d373e03c8c",
623 | "name": "Set Cookies",
624 | "dataMode": "params",
625 | "data": [],
626 | "rawModeData": null,
627 | "descriptionFormat": null,
628 | "description": "The cookie setter endpoint accepts a list of cookies and their values as part of URL parameters of a `GET` request. These cookies are saved and can be subsequently retrieved or deleted. The response of this request returns a JSON with all cookies listed.\n\nTo set your own set of cookies, simply replace the URL parameters \"foo1=bar1&foo2=bar2\" with your own set of key-value pairs.",
629 | "headers": "",
630 | "method": "GET",
631 | "pathVariables": {},
632 | "url": "https://echo.getpostman.com/cookies/set?foo1=bar1&foo2=bar",
633 | "preRequestScript": "",
634 | "tests": "var responseJSON;\ntry {\n tests[\"Body contains cookies\"] = responseBody.has(\"cookies\");\n responseJSON = JSON.parse(responseBody);\n tests[\"Body contains cookie foo1\"] = 'foo1' in responseJSON.cookies;\n tests[\"Body contains cookie foo2\"] = 'foo2' in responseJSON.cookies; \n}\ncatch (e) { }\n\ntests[\"Status code is 200\"] = responseCode.code === 200;\n\n",
635 | "currentHelper": "normal",
636 | "helperAttributes": {},
637 | "collectionId": "f695cab7-6878-eb55-7943-ad88e1ccfd65",
638 | "responses": [
639 | {
640 | "owner": 0,
641 | "lastUpdatedBy": "631643",
642 | "lastRevision": 277278568,
643 | "request": "96a24790-4951-ba7e-aa4f-fb40a45a7fcb",
644 | "id": "6c09f286-f74c-4d60-c349-f4a7ff7bac28",
645 | "name": "Cookies",
646 | "status": "",
647 | "responseCode": {
648 | "code": 200,
649 | "name": "OK"
650 | },
651 | "time": "3063",
652 | "headers": [
653 | {
654 | "name": "Access-Control-Allow-Credentials",
655 | "key": "Access-Control-Allow-Credentials",
656 | "value": "",
657 | "description": ""
658 | },
659 | {
660 | "name": "Access-Control-Allow-Headers",
661 | "key": "Access-Control-Allow-Headers",
662 | "value": "",
663 | "description": ""
664 | },
665 | {
666 | "name": "Access-Control-Allow-Methods",
667 | "key": "Access-Control-Allow-Methods",
668 | "value": "",
669 | "description": ""
670 | },
671 | {
672 | "name": "Access-Control-Allow-Origin",
673 | "key": "Access-Control-Allow-Origin",
674 | "value": "",
675 | "description": ""
676 | },
677 | {
678 | "name": "Connection",
679 | "key": "Connection",
680 | "value": "keep-alive",
681 | "description": ""
682 | },
683 | {
684 | "name": "Content-Encoding",
685 | "key": "Content-Encoding",
686 | "value": "gzip",
687 | "description": ""
688 | },
689 | {
690 | "name": "Content-Length",
691 | "key": "Content-Length",
692 | "value": "51",
693 | "description": ""
694 | },
695 | {
696 | "name": "Content-Type",
697 | "key": "Content-Type",
698 | "value": "application/json; charset=utf-8",
699 | "description": ""
700 | },
701 | {
702 | "name": "Date",
703 | "key": "Date",
704 | "value": "Thu, 29 Oct 2015 06:15:28 GMT",
705 | "description": ""
706 | },
707 | {
708 | "name": "Server",
709 | "key": "Server",
710 | "value": "nginx/1.6.2",
711 | "description": ""
712 | },
713 | {
714 | "name": "Vary",
715 | "key": "Vary",
716 | "value": "Accept-Encoding",
717 | "description": ""
718 | },
719 | {
720 | "name": "X-Powered-By",
721 | "key": "X-Powered-By",
722 | "value": "Sails ",
723 | "description": ""
724 | }
725 | ],
726 | "cookies": [],
727 | "mime": "",
728 | "text": "{\"cookies\":{\"foo1\":\"bar\",\"foo2\":\"bar\"}}",
729 | "language": "javascript",
730 | "rawDataType": "text",
731 | "state": {
732 | "size": "normal"
733 | },
734 | "previewType": "html",
735 | "searchResultScrolledTo": "-1",
736 | "version": null,
737 | "requestObject": "\"96a24790-4951-ba7e-aa4f-fb40a45a7fcb\"",
738 | "createdAt": "2016-05-25T12:29:57.000Z",
739 | "updatedAt": "2016-05-25T12:29:58.000Z",
740 | "write": true
741 | }
742 | ]
743 | },
744 | {
745 | "folder": "df815c41-a76b-4b5b-7129-ea59275f254b",
746 | "id": "42c867ca-e72b-3307-169b-26a478b00641",
747 | "name": "Basic Auth",
748 | "dataMode": "params",
749 | "data": [],
750 | "rawModeData": null,
751 | "descriptionFormat": null,
752 | "description": "This endpoint simulates a **basic-auth** protected endpoint. \nThe endpoint accepts a default username and password and returns a status code of `200 ok` only if the same is provided. \nOtherwise it will return a status code `401 unauthorized`.\n\n> Username: `postman`\n> \n> Password: `password`\n\nTo use this endpoint, send a request with the header `Authorization: Basic cG9zdG1hbjpwYXNzd29yZA==`. \nThe cryptic latter half of the header value is a base64 encoded concatenation of the default username and password. \nUsing Postman, to send this request, you can simply fill in the username and password in the \"Authorization\" tab and Postman will do the rest for you.\n\nTo know more about basic authentication, refer to the [Basic Access Authentication](https://en.wikipedia.org/wiki/Basic_access_authentication) wikipedia article.\nThe article on [authentication helpers](https://www.getpostman.com/docs/helpers#basic-auth?source=echo-collection-app-onboarding) elaborates how to use the same within the Postman app.",
753 | "headers": "Authorization: Basic cG9zdG1hbjpwYXNzd29yZA==\n",
754 | "method": "GET",
755 | "pathVariables": {},
756 | "url": "https://echo.getpostman.com/basic-auth",
757 | "preRequestScript": "",
758 | "tests": "tests[\"response code is 200\"] = responseCode.code === 200;\ntests[\"Body contains authenticated\"] = responseBody.has(\"authenticated\");",
759 | "currentHelper": "basicAuth",
760 | "helperAttributes": {
761 | "id": "basic",
762 | "username": "postman",
763 | "password": "password",
764 | "saveToRequest": true
765 | },
766 | "collectionId": "f695cab7-6878-eb55-7943-ad88e1ccfd65",
767 | "responses": [
768 | {
769 | "owner": 0,
770 | "lastUpdatedBy": "631643",
771 | "lastRevision": 277278560,
772 | "request": "ef90671a-ab14-16f5-0a57-41b32fc2a36f",
773 | "id": "97223e54-e9ac-810d-41df-6b53e1c917e4",
774 | "name": "200",
775 | "status": "",
776 | "responseCode": {
777 | "code": 200,
778 | "name": "OK"
779 | },
780 | "time": "377",
781 | "headers": [
782 | {
783 | "name": "Access-Control-Allow-Credentials",
784 | "key": "Access-Control-Allow-Credentials",
785 | "value": "",
786 | "description": ""
787 | },
788 | {
789 | "name": "Access-Control-Allow-Headers",
790 | "key": "Access-Control-Allow-Headers",
791 | "value": "",
792 | "description": ""
793 | },
794 | {
795 | "name": "Access-Control-Allow-Methods",
796 | "key": "Access-Control-Allow-Methods",
797 | "value": "",
798 | "description": ""
799 | },
800 | {
801 | "name": "Access-Control-Allow-Origin",
802 | "key": "Access-Control-Allow-Origin",
803 | "value": "",
804 | "description": ""
805 | },
806 | {
807 | "name": "Connection",
808 | "key": "Connection",
809 | "value": "keep-alive",
810 | "description": ""
811 | },
812 | {
813 | "name": "Content-Encoding",
814 | "key": "Content-Encoding",
815 | "value": "gzip",
816 | "description": ""
817 | },
818 | {
819 | "name": "Content-Length",
820 | "key": "Content-Length",
821 | "value": "42",
822 | "description": ""
823 | },
824 | {
825 | "name": "Content-Type",
826 | "key": "Content-Type",
827 | "value": "application/json; charset=utf-8",
828 | "description": ""
829 | },
830 | {
831 | "name": "Date",
832 | "key": "Date",
833 | "value": "Sat, 31 Oct 2015 06:38:25 GMT",
834 | "description": ""
835 | },
836 | {
837 | "name": "Server",
838 | "key": "Server",
839 | "value": "nginx/1.6.2",
840 | "description": ""
841 | },
842 | {
843 | "name": "Vary",
844 | "key": "Vary",
845 | "value": "Accept-Encoding",
846 | "description": ""
847 | },
848 | {
849 | "name": "X-Powered-By",
850 | "key": "X-Powered-By",
851 | "value": "Sails ",
852 | "description": ""
853 | }
854 | ],
855 | "cookies": [],
856 | "mime": "",
857 | "text": "{\"authenticated\":true}",
858 | "language": "javascript",
859 | "rawDataType": "text",
860 | "state": {
861 | "size": "normal"
862 | },
863 | "previewType": "html",
864 | "searchResultScrolledTo": "-1",
865 | "version": null,
866 | "requestObject": "\"ef90671a-ab14-16f5-0a57-41b32fc2a36f\"",
867 | "createdAt": "2016-05-25T12:29:57.000Z",
868 | "updatedAt": "2016-05-25T12:29:58.000Z",
869 | "write": true
870 | }
871 | ]
872 | },
873 | {
874 | "folder": "930f54b4-c5cd-2363-7cf5-b9022d3c0aae",
875 | "id": "5d3b31c0-fa26-ee03-5c1b-3715825d811d",
876 | "name": "Deflate Compressed Response",
877 | "dataMode": "params",
878 | "data": [],
879 | "rawModeData": null,
880 | "descriptionFormat": null,
881 | "description": "This endpoint returns the response using [deflate compression algoritm](https://en.wikipedia.org/wiki/DEFLATE). \nThe uncompressed response is a JSON string containing the details of the request sent by the client. For this endpoint to work, one should request with `Accept-encoding` header containing `deflate` as part of its value. Postman supports gzip, deflate and SDCH decoding and automatically sends them as part of the request.\n\nHTTP Compression allows the server to send responses in a compressed format, which is uncompressed by the client before processing. This reduces network bandwidth consumption at the cost of increase in CPU usage.\nTo know more about this, refer the [HTTP Compression](https://en.wikipedia.org/wiki/HTTP_compression) wikipedia article.",
882 | "headers": "",
883 | "method": "GET",
884 | "pathVariables": {},
885 | "url": "https://echo.getpostman.com/deflate",
886 | "preRequestScript": "",
887 | "tests": "tests[\"response code is 200\"] = responseCode.code === 200;\n\ntry {\n var data = JSON.parse(responseBody);\n tests[\"Body contains deflated\"] = responseBody.has(\"deflated\");\n tests[\"Body contains headers\"] = responseBody.has(\"headers\");\n tests[\"Body contains method\"] = responseBody.has(\"method\");\n}\ncatch(e) {\n console.log('Cannot parse response,probably not a JSON');\n}\n",
888 | "currentHelper": "normal",
889 | "helperAttributes": {},
890 | "collectionId": "f695cab7-6878-eb55-7943-ad88e1ccfd65"
891 | },
892 | {
893 | "folder": "930f54b4-c5cd-2363-7cf5-b9022d3c0aae",
894 | "id": "6cfd22d8-26cc-7d3e-cf50-16d400211a76",
895 | "name": "Response Status Code",
896 | "dataMode": "params",
897 | "data": [],
898 | "rawModeData": null,
899 | "descriptionFormat": null,
900 | "description": "This endpoint allows one to instruct the server which status code to respond with.\n\nEvery response is accompanied by a status code. The status code provides a summary of the nature of response sent by the server. For example, a status code of `200` means everything is okay with the response and a code of `404` implies that the requested URL does not exist on server. \nA list of all valid HTTP status code can be found at the [List of Status Codes](https://en.wikipedia.org/wiki/List_of_HTTP_status_codes) wikipedia article. When using Postman, the response status code is described for easy reference.\n\nNote that if an invalid status code is requested to be sent, the server returns a status code of `400 Bad Request`.",
901 | "headers": "",
902 | "method": "GET",
903 | "pathVariables": {},
904 | "url": "https://echo.getpostman.com/status/200",
905 | "preRequestScript": "",
906 | "tests": "var responseJSON;\ntry {\n responseJSON = JSON.parse(responseBody); \n tests[\"Status equals 200\"] = responseJSON.status === 200;\n}\ncatch (e) { }\ntests[\"Body contains status\"] = responseBody.has(\"status\");\n\n",
907 | "currentHelper": "normal",
908 | "helperAttributes": {},
909 | "collectionId": "f695cab7-6878-eb55-7943-ad88e1ccfd65",
910 | "responses": [
911 | {
912 | "owner": 0,
913 | "lastUpdatedBy": "631643",
914 | "lastRevision": 277278566,
915 | "request": {
916 | "url": "https://echo.getpostman.com/status/200",
917 | "headers": [],
918 | "data": [],
919 | "method": "GET",
920 | "dataMode": "params"
921 | },
922 | "id": "a2bda27d-2c7b-eb8e-1740-be4e1fe9a079",
923 | "name": "200",
924 | "status": "",
925 | "responseCode": {
926 | "code": 200,
927 | "name": "OK"
928 | },
929 | "time": "251",
930 | "headers": [
931 | {
932 | "name": "Access-Control-Allow-Credentials",
933 | "key": "Access-Control-Allow-Credentials",
934 | "value": "",
935 | "description": ""
936 | },
937 | {
938 | "name": "Access-Control-Allow-Headers",
939 | "key": "Access-Control-Allow-Headers",
940 | "value": "",
941 | "description": ""
942 | },
943 | {
944 | "name": "Access-Control-Allow-Methods",
945 | "key": "Access-Control-Allow-Methods",
946 | "value": "",
947 | "description": ""
948 | },
949 | {
950 | "name": "Access-Control-Allow-Origin",
951 | "key": "Access-Control-Allow-Origin",
952 | "value": "",
953 | "description": ""
954 | },
955 | {
956 | "name": "Connection",
957 | "key": "Connection",
958 | "value": "keep-alive",
959 | "description": ""
960 | },
961 | {
962 | "name": "Content-Length",
963 | "key": "Content-Length",
964 | "value": "14",
965 | "description": ""
966 | },
967 | {
968 | "name": "Content-Type",
969 | "key": "Content-Type",
970 | "value": "application/json; charset=utf-8",
971 | "description": ""
972 | },
973 | {
974 | "name": "Date",
975 | "key": "Date",
976 | "value": "Thu, 31 Mar 2016 11:58:47 GMT",
977 | "description": ""
978 | },
979 | {
980 | "name": "ETag",
981 | "key": "ETag",
982 | "value": "W/\"e-1056260003\"",
983 | "description": ""
984 | },
985 | {
986 | "name": "Server",
987 | "key": "Server",
988 | "value": "nginx/1.6.2",
989 | "description": ""
990 | },
991 | {
992 | "name": "Vary",
993 | "key": "Vary",
994 | "value": "Accept-Encoding",
995 | "description": ""
996 | },
997 | {
998 | "name": "X-Powered-By",
999 | "key": "X-Powered-By",
1000 | "value": "Sails ",
1001 | "description": ""
1002 | }
1003 | ],
1004 | "cookies": [
1005 | {
1006 | "domain": ".getpostman.com",
1007 | "expirationDate": 1460718898.059833,
1008 | "hostOnly": false,
1009 | "httpOnly": false,
1010 | "name": "getpostmanlogin",
1011 | "path": "/",
1012 | "secure": false,
1013 | "session": false,
1014 | "storeId": "0",
1015 | "value": "yes"
1016 | },
1017 | {
1018 | "domain": ".getpostman.com",
1019 | "expirationDate": 1460718898.059992,
1020 | "hostOnly": false,
1021 | "httpOnly": false,
1022 | "name": "postman.sid",
1023 | "path": "/",
1024 | "secure": false,
1025 | "session": false,
1026 | "storeId": "0",
1027 | "value": "df0c0256028d7ec4d641f766104a9571a8e249685bbc667d7cee030bbf44d3209495c70c03248e31e678a93812591d5e12187a8e99bf6bc5e80c40903f6ff6226938f24e413c0ffa613a7372064ec44a8594e8d3ede6945e34394f369573feeebc4a73a3e24b8c9ac18a53704addb5fd3f71f1ede488ff551feb059e9c1fb208164814e45e0312c4df8ea6e83c26702f42ae634c6afbe82d57c857bbf5598b5527961c1c28688dc2580070a4389f0cf4ec0a179b5b9c11b2ecbaa5460d374065bf5c7a3add9505df0fa89acb9f227f05ed2d4c6b58c39d6d728bd49f6f323ae67d4a75882aa7682f5d6fc5b981ba411d94aa93970bfaefa1953a73e440d50d012b5f288975c888e2345ee7777e746fb5aed3a7b2dbc087c6456621aa78c24a3c17c5f96cf59844933249a352f631e2008cffac6faf06d0e253dcc01cf0067bf56c1fbc5ed61fec1861b60c5accf35ffc2e56154a113004fa1db9d7171c3af8fc063918554092f5"
1028 | },
1029 | {
1030 | "domain": ".echo.getpostman.com",
1031 | "expirationDate": 1522494981,
1032 | "hostOnly": false,
1033 | "httpOnly": false,
1034 | "name": "_ga",
1035 | "path": "/",
1036 | "secure": false,
1037 | "session": false,
1038 | "storeId": "0",
1039 | "value": "GA1.3.1703443399.1459422978"
1040 | },
1041 | {
1042 | "domain": "echo.getpostman.com",
1043 | "hostOnly": true,
1044 | "httpOnly": true,
1045 | "name": "sails.sid",
1046 | "path": "/",
1047 | "secure": false,
1048 | "session": true,
1049 | "storeId": "0",
1050 | "value": "s%3AvuHU0EKeDbyNjVrEc7U30dMPzVu8CRaD.GOV1H9olcVzXqrwqP%2BC%2B6MVj2UczXivcN00jgPoDYfs"
1051 | }
1052 | ],
1053 | "mime": "",
1054 | "text": "{\"status\":200}",
1055 | "language": "javascript",
1056 | "rawDataType": "text",
1057 | "state": {
1058 | "size": "normal"
1059 | },
1060 | "previewType": "html",
1061 | "searchResultScrolledTo": "-1",
1062 | "version": null,
1063 | "requestObject": "{\"url\":\"https://echo.getpostman.com/status/200\",\"headers\":[],\"data\":[],\"method\":\"GET\",\"dataMode\":\"params\"}",
1064 | "createdAt": "2016-05-25T12:29:57.000Z",
1065 | "updatedAt": "2016-05-25T12:29:58.000Z",
1066 | "write": true
1067 | }
1068 | ]
1069 | },
1070 | {
1071 | "folder": "09ddd67c-13fe-4626-8dd4-fc64f1fc27b7",
1072 | "id": "70ed7920-ead1-2d20-645a-c716ab0fd137",
1073 | "name": "DigestAuth Request",
1074 | "dataMode": "params",
1075 | "data": [
1076 | {
1077 | "key": "code",
1078 | "value": "xWnkliVQJURqB2x1",
1079 | "type": "text",
1080 | "enabled": true
1081 | },
1082 | {
1083 | "key": "grant_type",
1084 | "value": "authorization_code",
1085 | "type": "text",
1086 | "enabled": true
1087 | },
1088 | {
1089 | "key": "redirect_uri",
1090 | "value": "https://www.getpostman.com/oauth2/callback",
1091 | "type": "text",
1092 | "enabled": true
1093 | },
1094 | {
1095 | "key": "client_id",
1096 | "value": "abc123",
1097 | "type": "text",
1098 | "enabled": true
1099 | },
1100 | {
1101 | "key": "client_secret",
1102 | "value": "ssh-secret",
1103 | "type": "text",
1104 | "enabled": true
1105 | }
1106 | ],
1107 | "rawModeData": null,
1108 | "descriptionFormat": null,
1109 | "description": "Performing a simple `GET` request to this endpoint returns status code `401 Unauthorized` with `WWW-Authenticate` header containing information to successfully authenticate subsequent requests.\nThe `WWW-Authenticate` header must be processed to extract `realm` and `nonce` values to hash subsequent requests.\n\nWhen this request is executed within Postman, the script attached with this request does the hard work of extracting realm and nonce from the header and set it as [global variables](https://www.getpostman.com/docs/environments#global-variables?source=echo-collection-app-onboarding) named `echo_digest_nonce` and `echo_digest_realm`.\nThese variables are re-used in subsequent request for seamless integration of the two requests.",
1110 | "headers": "",
1111 | "method": "GET",
1112 | "pathVariables": {},
1113 | "url": "https://echo.getpostman.com/digest-auth",
1114 | "preRequestScript": "",
1115 | "tests": "tests[\"response code is 401\"] = responseCode.code === 401;\ntests[\"response has WWW-Authenticate header\"] = (postman.getResponseHeader('WWW-Authenticate'));\n\nvar authenticateHeader = postman.getResponseHeader('WWW-Authenticate'),\n realmStart = authenticateHeader.indexOf('\"',authenticateHeader.indexOf(\"realm\")) + 1 ,\n realmEnd = authenticateHeader.indexOf('\"',realmStart),\n realm = authenticateHeader.slice(realmStart,realmEnd),\n nonceStart = authenticateHeader.indexOf('\"',authenticateHeader.indexOf(\"nonce\")) + 1,\n nonceEnd = authenticateHeader.indexOf('\"',nonceStart),\n nonce = authenticateHeader.slice(nonceStart,nonceEnd);\n \npostman.setGlobalVariable('echo_digest_realm', realm);\npostman.setGlobalVariable('echo_digest_nonce', nonce);",
1116 | "currentHelper": "normal",
1117 | "helperAttributes": {},
1118 | "collectionId": "f695cab7-6878-eb55-7943-ad88e1ccfd65"
1119 | },
1120 | {
1121 | "folder": "df815c41-a76b-4b5b-7129-ea59275f254b",
1122 | "id": "843acf02-a33c-c4bb-d742-c07b9212e4b0",
1123 | "name": "Hawk Auth",
1124 | "dataMode": "params",
1125 | "data": [
1126 | {
1127 | "key": "access_token",
1128 | "value": "xyz1",
1129 | "type": "text",
1130 | "enabled": true
1131 | },
1132 | {
1133 | "key": "id",
1134 | "value": "U1",
1135 | "type": "text",
1136 | "enabled": true
1137 | },
1138 | {
1139 | "key": "server_secret",
1140 | "value": "zeppelin",
1141 | "type": "text",
1142 | "enabled": true
1143 | },
1144 | {
1145 | "key": "admin",
1146 | "value": "true",
1147 | "type": "text",
1148 | "enabled": true
1149 | }
1150 | ],
1151 | "rawModeData": null,
1152 | "descriptionFormat": "html",
1153 | "description": "This endpoint is a Hawk Authentication protected endpoint. [Hawk authentication](https://github.com/hueniverse/hawk) is a widely used protocol for protecting API endpoints. One of Hawk's main goals is to enable HTTP authentication for services that do not use TLS (although it can be used in conjunction with TLS as well).\n\nIn order to use this endpoint, select the \"Hawk Auth\" helper inside Postman, and set the following values:\n\nHawk Auth ID: `dh37fgj492je`\n\nHawk Auth Key: `werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn`\n\nAlgorithm: `sha256`\n\nThe rest of the values are optional, and can be left blank. Hitting send should give you a response with a status code of 200 OK.",
1154 | "headers": "",
1155 | "method": "GET",
1156 | "pathVariables": {},
1157 | "url": "https://echo.getpostman.com/auth/hawk",
1158 | "preRequestScript": "",
1159 | "tests": "tests[\"Status code is 200\"] = responseCode.code === 200;",
1160 | "currentHelper": "hawkAuth",
1161 | "helperAttributes": {
1162 | "id": "hawk",
1163 | "hawk_id": "dh37fgj492je",
1164 | "hawk_key": "werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn",
1165 | "algorithm": "sha256",
1166 | "user": "",
1167 | "saveToRequest": true,
1168 | "nonce": "RZKGNz",
1169 | "timestamp": ""
1170 | },
1171 | "collectionId": "f695cab7-6878-eb55-7943-ad88e1ccfd65",
1172 | "responses": [
1173 | {
1174 | "owner": 0,
1175 | "lastUpdatedBy": "631643",
1176 | "lastRevision": 277278564,
1177 | "request": {
1178 | "url": "https://echo.getpostman.com/auth/hawk",
1179 | "headers": [
1180 | {
1181 | "key": "Authorization",
1182 | "type": "text",
1183 | "name": "Authorization",
1184 | "value": "Hawk id=\"dh37fgj492je\", ts=\"1459422734\", nonce=\"XiwiCU\", mac=\"KzMHk67BYCC9zZqRy5hRdWFEFLHX5bNlRWGdmOAWKp0=\""
1185 | }
1186 | ],
1187 | "data": [
1188 | {
1189 | "key": "access_token",
1190 | "value": "xyz1",
1191 | "type": "text",
1192 | "enabled": true
1193 | },
1194 | {
1195 | "key": "id",
1196 | "value": "U1",
1197 | "type": "text",
1198 | "enabled": true
1199 | },
1200 | {
1201 | "key": "server_secret",
1202 | "value": "zeppelin",
1203 | "type": "text",
1204 | "enabled": true
1205 | },
1206 | {
1207 | "key": "admin",
1208 | "value": "true",
1209 | "type": "text",
1210 | "enabled": true
1211 | }
1212 | ],
1213 | "method": "GET",
1214 | "dataMode": "params"
1215 | },
1216 | "id": "8bcfebdc-a6fe-7607-cef3-7ee28a0b75a2",
1217 | "name": "Success",
1218 | "status": "",
1219 | "responseCode": {
1220 | "code": 200,
1221 | "name": "OK"
1222 | },
1223 | "time": "1855",
1224 | "headers": [
1225 | {
1226 | "name": "Access-Control-Allow-Credentials",
1227 | "key": "Access-Control-Allow-Credentials",
1228 | "value": "",
1229 | "description": ""
1230 | },
1231 | {
1232 | "name": "Access-Control-Allow-Headers",
1233 | "key": "Access-Control-Allow-Headers",
1234 | "value": "",
1235 | "description": ""
1236 | },
1237 | {
1238 | "name": "Access-Control-Allow-Methods",
1239 | "key": "Access-Control-Allow-Methods",
1240 | "value": "",
1241 | "description": ""
1242 | },
1243 | {
1244 | "name": "Access-Control-Allow-Origin",
1245 | "key": "Access-Control-Allow-Origin",
1246 | "value": "",
1247 | "description": ""
1248 | },
1249 | {
1250 | "name": "Connection",
1251 | "key": "Connection",
1252 | "value": "keep-alive",
1253 | "description": ""
1254 | },
1255 | {
1256 | "name": "Content-Encoding",
1257 | "key": "Content-Encoding",
1258 | "value": "gzip",
1259 | "description": ""
1260 | },
1261 | {
1262 | "name": "Content-Type",
1263 | "key": "Content-Type",
1264 | "value": "application/json",
1265 | "description": ""
1266 | },
1267 | {
1268 | "name": "Date",
1269 | "key": "Date",
1270 | "value": "Thu, 31 Mar 2016 11:12:16 GMT",
1271 | "description": ""
1272 | },
1273 | {
1274 | "name": "Server",
1275 | "key": "Server",
1276 | "value": "nginx/1.6.2",
1277 | "description": ""
1278 | },
1279 | {
1280 | "name": "Server-Authorization",
1281 | "key": "Server-Authorization",
1282 | "value": "Hawk mac=\"vRrUzDdcHu2NaNts/r4zg2xmXMdX8wPiTGTM398BDRg=\", hash=\"qmtflETMybaZiOQ2dLT17yiRunFT5OCIxZRZ0boQaiE=\"",
1283 | "description": ""
1284 | },
1285 | {
1286 | "name": "Vary",
1287 | "key": "Vary",
1288 | "value": "Accept-Encoding",
1289 | "description": ""
1290 | },
1291 | {
1292 | "name": "X-Powered-By",
1293 | "key": "X-Powered-By",
1294 | "value": "Sails ",
1295 | "description": ""
1296 | },
1297 | {
1298 | "name": "transfer-encoding",
1299 | "key": "transfer-encoding",
1300 | "value": "chunked",
1301 | "description": ""
1302 | }
1303 | ],
1304 | "cookies": [
1305 | {
1306 | "domain": ".getpostman.com",
1307 | "expirationDate": 1460717668.06945,
1308 | "hostOnly": false,
1309 | "httpOnly": false,
1310 | "name": "getpostmanlogin",
1311 | "path": "/",
1312 | "secure": false,
1313 | "session": false,
1314 | "storeId": "0",
1315 | "value": "yes"
1316 | },
1317 | {
1318 | "domain": ".getpostman.com",
1319 | "expirationDate": 1460717668.069509,
1320 | "hostOnly": false,
1321 | "httpOnly": false,
1322 | "name": "postman.sid",
1323 | "path": "/",
1324 | "secure": false,
1325 | "session": false,
1326 | "storeId": "0",
1327 | "value": "9f887f3b7f14b8c29ac4dc4109381b0b89a76e785c7b34251d6c8025b41b24013d2aa49f40e2deac19cbf0594dd984169455534d91ff98d4d1868d67ac857017629f137926e3a04a616bb83a2fb5ab9e6cbea9579ed5d5c1155d47545d72aad5be99f4abd0a7130805b3807d70cd507171dbe9d950d8e35a853f9ec075f5a767c95df4d57f7d521b66605b3bda3801700e26e651d1129c798b729ee3b91702d43ae64ab226c3f426893753def772c15442a7552dc84a3c773d6099a50b0a6af940b64c8176fedfcecd5fc31ccfc3bbc0124bfdaa0d62e4252d4aafb46a3c10963d12391e1fa97a1c0f19a636f57a3ac8cc35567d1cb6cb53b77f8adde3f6754a765596d7d00bdeb9acb5cc8d115e7c3f50ec3228e34d3e6c7464e9039b01868e03d10e9f87772397602453e9e91205de7b86021fad06eb26e69298e99ff1597a670faeb310f8c092041d544851de84f2bee89a92123da6eea286210524035c85361e2af42166a6"
1328 | },
1329 | {
1330 | "domain": "echo.getpostman.com",
1331 | "hostOnly": true,
1332 | "httpOnly": true,
1333 | "name": "sails.sid",
1334 | "path": "/",
1335 | "secure": false,
1336 | "session": true,
1337 | "storeId": "0",
1338 | "value": "s%3AryJV7v-PE4PuTjBK6nH5XOynQ4atuATV.n17KcaLhVmV8TBHNLwdwXgGR7lmqs3i478WPlTbRgZ4"
1339 | }
1340 | ],
1341 | "mime": "",
1342 | "text": "{\"status\":\"pass\",\"message\":\"Hawk Authentication successful\"}",
1343 | "language": "javascript",
1344 | "rawDataType": "text",
1345 | "state": {
1346 | "size": "normal"
1347 | },
1348 | "previewType": "html",
1349 | "searchResultScrolledTo": "-1",
1350 | "version": null,
1351 | "requestObject": "{\"url\":\"https://echo.getpostman.com/auth/hawk\",\"headers\":[{\"key\":\"Authorization\",\"type\":\"text\",\"name\":\"Authorization\",\"value\":\"Hawk id=\\\"dh37fgj492je\\\", ts=\\\"1459422734\\\", nonce=\\\"XiwiCU\\\", mac=\\\"KzMHk67BYCC9zZqRy5hRdWFEFLHX5bNlRWGdmOAWKp0=\\\"\"}],\"data\":[{\"key\":\"access_token\",\"value\":\"xyz1\",\"type\":\"text\",\"enabled\":true},{\"key\":\"id\",\"value\":\"U1\",\"type\":\"text\",\"enabled\":true},{\"key\":\"server_secret\",\"value\":\"zeppelin\",\"type\":\"text\",\"enabled\":true},{\"key\":\"admin\",\"value\":\"true\",\"type\":\"text\",\"enabled\":true}],\"method\":\"GET\",\"dataMode\":\"params\"}",
1352 | "createdAt": "2016-05-25T12:29:57.000Z",
1353 | "updatedAt": "2016-05-25T12:29:58.000Z",
1354 | "write": true
1355 | }
1356 | ]
1357 | },
1358 | {
1359 | "folder": "9a4c3bce-30f7-a496-c9ec-78afecbf1545",
1360 | "id": "8c53212f-42cd-cb37-6e02-08c47a7c8bb1",
1361 | "name": "PATCH Request",
1362 | "dataMode": "raw",
1363 | "data": [],
1364 | "descriptionFormat": null,
1365 | "description": "The HTTP `PATCH` method is used to update resources on a server. The exact\nuse of `PATCH` requests depends on the server in question. There are a number\nof server implementations which handle `PATCH` differently. Technically, \n`PATCH` supports both Query String parameters and a Request Body.\n\nThis endpoint accepts an HTTP `PATCH` request and provides debug information\nsuch as the HTTP headers, Query String arguments, and the Request Body.",
1366 | "headers": "",
1367 | "method": "PATCH",
1368 | "pathVariables": {},
1369 | "url": "https://echo.getpostman.com/patch",
1370 | "preRequestScript": "",
1371 | "tests": "tests[\"Body contains files\"] = responseBody.has(\"files\");\ntests[\"Body contains args\"] = responseBody.has(\"args\");\ntests[\"Body contains form\"] = responseBody.has(\"form\");\ntests[\"Body contains headers\"] = responseBody.has(\"headers\");\ntests[\"Body contains url\"] = responseBody.has(\"url\");\n\nvar responseJSON;\n\ntry { responseJSON = JSON.parse(responseBody); }\ncatch (e) { }\n\ntests[\"Data has been passed\"] = (responseJSON && responseJSON.data && responseJSON.data.length)",
1372 | "currentHelper": "normal",
1373 | "helperAttributes": {},
1374 | "collectionId": "f695cab7-6878-eb55-7943-ad88e1ccfd65",
1375 | "rawModeData": "Curabitur auctor, elit nec pulvinar porttitor, ex augue condimentum enim, eget suscipit urna felis quis neque.\nSuspendisse sit amet luctus massa, nec venenatis mi. Suspendisse tincidunt massa at nibh efficitur fringilla. Nam quis congue mi. Etiam volutpat."
1376 | },
1377 | {
1378 | "folder": "37368024-f6a8-0f70-85fc-7e876cde9e33",
1379 | "id": "8dc08eee-a543-7c1c-297f-b0b7040c35c6",
1380 | "name": "Get Cookies",
1381 | "dataMode": "params",
1382 | "data": [],
1383 | "rawModeData": null,
1384 | "descriptionFormat": null,
1385 | "description": "Use this endpoint to get a list of all cookies that are stored with respect to this domain. Whatever key-value pairs that has been previously set by calling the \"Set Cookies\" endpoint, will be returned as response JSON.",
1386 | "headers": "",
1387 | "method": "GET",
1388 | "pathVariables": {},
1389 | "url": "https://echo.getpostman.com/cookies",
1390 | "preRequestScript": "",
1391 | "tests": "var responseJSON;\ntry {\n tests[\"Body contains cookies\"] = responseBody.has(\"cookies\");\n responseJSON = JSON.parse(responseBody);\n tests[\"Cookies object is empty\"] = (Object.keys(responseJSON.cookies).length > 0)\n}\ncatch (e) { }\n\ntests[\"Status code is 200\"] = responseCode.code === 200;\n",
1392 | "currentHelper": "normal",
1393 | "helperAttributes": {},
1394 | "collectionId": "f695cab7-6878-eb55-7943-ad88e1ccfd65",
1395 | "responses": [
1396 | {
1397 | "owner": 0,
1398 | "lastUpdatedBy": "631643",
1399 | "lastRevision": 277278565,
1400 | "request": "4118ca21-f216-410f-510c-2d0e465022c5",
1401 | "id": "403109d9-a2e7-2bf7-9af3-1282aa7d74cd",
1402 | "name": "Cookies",
1403 | "status": "",
1404 | "responseCode": {
1405 | "code": 200,
1406 | "name": "OK"
1407 | },
1408 | "time": "462",
1409 | "headers": [
1410 | {
1411 | "name": "Access-Control-Allow-Credentials",
1412 | "key": "Access-Control-Allow-Credentials",
1413 | "value": "",
1414 | "description": ""
1415 | },
1416 | {
1417 | "name": "Access-Control-Allow-Headers",
1418 | "key": "Access-Control-Allow-Headers",
1419 | "value": "",
1420 | "description": ""
1421 | },
1422 | {
1423 | "name": "Access-Control-Allow-Methods",
1424 | "key": "Access-Control-Allow-Methods",
1425 | "value": "",
1426 | "description": ""
1427 | },
1428 | {
1429 | "name": "Access-Control-Allow-Origin",
1430 | "key": "Access-Control-Allow-Origin",
1431 | "value": "",
1432 | "description": ""
1433 | },
1434 | {
1435 | "name": "Connection",
1436 | "key": "Connection",
1437 | "value": "keep-alive",
1438 | "description": ""
1439 | },
1440 | {
1441 | "name": "Content-Encoding",
1442 | "key": "Content-Encoding",
1443 | "value": "gzip",
1444 | "description": ""
1445 | },
1446 | {
1447 | "name": "Content-Length",
1448 | "key": "Content-Length",
1449 | "value": "46",
1450 | "description": ""
1451 | },
1452 | {
1453 | "name": "Content-Type",
1454 | "key": "Content-Type",
1455 | "value": "application/json; charset=utf-8",
1456 | "description": ""
1457 | },
1458 | {
1459 | "name": "Date",
1460 | "key": "Date",
1461 | "value": "Thu, 29 Oct 2015 06:16:29 GMT",
1462 | "description": ""
1463 | },
1464 | {
1465 | "name": "Server",
1466 | "key": "Server",
1467 | "value": "nginx/1.6.2",
1468 | "description": ""
1469 | },
1470 | {
1471 | "name": "Vary",
1472 | "key": "Vary",
1473 | "value": "Accept-Encoding",
1474 | "description": ""
1475 | },
1476 | {
1477 | "name": "X-Powered-By",
1478 | "key": "X-Powered-By",
1479 | "value": "Sails ",
1480 | "description": ""
1481 | }
1482 | ],
1483 | "cookies": [],
1484 | "mime": "",
1485 | "text": "{\"cookies\":{\"foo2\":\"bar\"}}",
1486 | "language": "javascript",
1487 | "rawDataType": "text",
1488 | "state": {
1489 | "size": "normal"
1490 | },
1491 | "previewType": "html",
1492 | "searchResultScrolledTo": "-1",
1493 | "version": null,
1494 | "requestObject": "\"4118ca21-f216-410f-510c-2d0e465022c5\"",
1495 | "createdAt": "2016-05-25T12:29:57.000Z",
1496 | "updatedAt": "2016-05-25T12:29:58.000Z",
1497 | "write": true
1498 | }
1499 | ]
1500 | },
1501 | {
1502 | "folder": "09ddd67c-13fe-4626-8dd4-fc64f1fc27b7",
1503 | "id": "a4c04e32-72cf-0475-07dc-89c23f85cf0c",
1504 | "name": "DigestAuth Success",
1505 | "dataMode": "params",
1506 | "data": [],
1507 | "rawModeData": null,
1508 | "descriptionFormat": null,
1509 | "description": "This endpoint sends a hashed Digest Authorization header to gain access to a valid `200 Ok` response code. In Postman, it uses the stored [global variables](https://www.getpostman.com/docs/environments#gloval-variables?source=echo-collection-app-onboarding), `echo_digest_realm` and `echo_digest_nonce`, to generate the hashed authorisation header.\n\nWithin Postman, for this request to successfully authenticate, running the previous request \"DigestAuth Request\" stores the relevant information within the global variables.",
1510 | "headers": "Authorization: Digest username=\"postman\", realm=\"Users\", nonce=\"ni1LiL0O37PRRhofWdCLmwFsnEtH1lew\", uri=\"/digest-auth\", response=\"254679099562cf07df9b6f5d8d15db44\", opaque=\"\"\n",
1511 | "method": "GET",
1512 | "pathVariables": {},
1513 | "url": "https://echo.getpostman.com/digest-auth",
1514 | "preRequestScript": "",
1515 | "tests": "tests[\"response code is 200\"] = responseCode.code === 200;\ntests[\"body contains authenticated\"] = responseBody.has(\"authenticated\");",
1516 | "currentHelper": "digestAuth",
1517 | "helperAttributes": {
1518 | "id": "digest",
1519 | "time": 1446551845396,
1520 | "algorithm": "MD5",
1521 | "username": "postman",
1522 | "realm": "{{echo_digest_realm}}",
1523 | "password": "password",
1524 | "nonce": "{{echo_digest_nonce}}",
1525 | "nonceCount": "",
1526 | "clientNonce": "",
1527 | "opaque": "",
1528 | "qop": "",
1529 | "saveToRequest": true
1530 | },
1531 | "collectionId": "f695cab7-6878-eb55-7943-ad88e1ccfd65",
1532 | "responses": [
1533 | {
1534 | "owner": 0,
1535 | "lastUpdatedBy": "631643",
1536 | "lastRevision": 277278567,
1537 | "request": "eecb504e-1736-d34c-990a-b86d36f06ddd",
1538 | "id": "50a1e424-f5a6-3017-3777-6c5d0d381be0",
1539 | "name": "200",
1540 | "status": "",
1541 | "responseCode": {
1542 | "code": 200,
1543 | "name": "OK"
1544 | },
1545 | "time": "9843",
1546 | "headers": [
1547 | {
1548 | "name": "Access-Control-Allow-Credentials",
1549 | "key": "Access-Control-Allow-Credentials",
1550 | "value": "",
1551 | "description": ""
1552 | },
1553 | {
1554 | "name": "Access-Control-Allow-Headers",
1555 | "key": "Access-Control-Allow-Headers",
1556 | "value": "",
1557 | "description": ""
1558 | },
1559 | {
1560 | "name": "Access-Control-Allow-Methods",
1561 | "key": "Access-Control-Allow-Methods",
1562 | "value": "",
1563 | "description": ""
1564 | },
1565 | {
1566 | "name": "Access-Control-Allow-Origin",
1567 | "key": "Access-Control-Allow-Origin",
1568 | "value": "",
1569 | "description": ""
1570 | },
1571 | {
1572 | "name": "Connection",
1573 | "key": "Connection",
1574 | "value": "keep-alive",
1575 | "description": ""
1576 | },
1577 | {
1578 | "name": "Content-Encoding",
1579 | "key": "Content-Encoding",
1580 | "value": "gzip",
1581 | "description": ""
1582 | },
1583 | {
1584 | "name": "Content-Length",
1585 | "key": "Content-Length",
1586 | "value": "42",
1587 | "description": ""
1588 | },
1589 | {
1590 | "name": "Content-Type",
1591 | "key": "Content-Type",
1592 | "value": "application/json; charset=utf-8",
1593 | "description": ""
1594 | },
1595 | {
1596 | "name": "Date",
1597 | "key": "Date",
1598 | "value": "Thu, 29 Oct 2015 06:17:51 GMT",
1599 | "description": ""
1600 | },
1601 | {
1602 | "name": "Server",
1603 | "key": "Server",
1604 | "value": "nginx/1.6.2",
1605 | "description": ""
1606 | },
1607 | {
1608 | "name": "Vary",
1609 | "key": "Vary",
1610 | "value": "Accept-Encoding",
1611 | "description": ""
1612 | },
1613 | {
1614 | "name": "X-Powered-By",
1615 | "key": "X-Powered-By",
1616 | "value": "Sails ",
1617 | "description": ""
1618 | }
1619 | ],
1620 | "cookies": [],
1621 | "mime": "",
1622 | "text": "{\"authenticated\":true}",
1623 | "language": "javascript",
1624 | "rawDataType": "text",
1625 | "state": {
1626 | "size": "normal"
1627 | },
1628 | "previewType": "html",
1629 | "searchResultScrolledTo": "-1",
1630 | "version": null,
1631 | "requestObject": "\"eecb504e-1736-d34c-990a-b86d36f06ddd\"",
1632 | "createdAt": "2016-05-25T12:29:57.000Z",
1633 | "updatedAt": "2016-05-25T12:29:58.000Z",
1634 | "write": true
1635 | }
1636 | ]
1637 | },
1638 | {
1639 | "id": "a4f24593-448b-88de-963f-eeb952d38a57",
1640 | "headers": "",
1641 | "url": "https://echo.getpostman.com/cookies/delete?foo1",
1642 | "preRequestScript": "",
1643 | "pathVariables": {},
1644 | "method": "GET",
1645 | "data": [],
1646 | "dataMode": "params",
1647 | "tests": "var responseJSON;\ntry {\n tests[\"Body contains cookies\"] = responseBody.has(\"cookies\");\n responseJSON = JSON.parse(responseBody);\n tests[\"Body contains cookie foo1\"] = ('foo1' in responseJSON.cookies);\n tests[\"Body does not contain cookie foo2\"] = !('foo2' in responseJSON.cookies);\n}\ncatch (e) { }\n\ntests[\"Status code is 200\"] = responseCode.code === 200;\n",
1648 | "currentHelper": "normal",
1649 | "helperAttributes": {},
1650 | "time": 1466082161277,
1651 | "name": "Delete Cookies",
1652 | "description": "One or more cookies that has been set for this domain can be deleted by providing the cookie names as part of the URL parameter. The response of this request is a JSON containing the list of currently set cookies.",
1653 | "collectionId": "f695cab7-6878-eb55-7943-ad88e1ccfd65",
1654 | "responses": [
1655 | {
1656 | "owner": 0,
1657 | "lastUpdatedBy": "631643",
1658 | "lastRevision": 277278563,
1659 | "request": "4ac1e980-6990-fc1d-5f80-4e5cedce9812",
1660 | "id": "522b3689-fb79-32fe-a253-7fb170b65555",
1661 | "name": "Cookies Response",
1662 | "status": "",
1663 | "responseCode": {
1664 | "code": 200,
1665 | "name": "OK"
1666 | },
1667 | "time": "1417",
1668 | "headers": [
1669 | {
1670 | "name": "Access-Control-Allow-Credentials",
1671 | "key": "Access-Control-Allow-Credentials",
1672 | "value": "",
1673 | "description": ""
1674 | },
1675 | {
1676 | "name": "Access-Control-Allow-Headers",
1677 | "key": "Access-Control-Allow-Headers",
1678 | "value": "",
1679 | "description": ""
1680 | },
1681 | {
1682 | "name": "Access-Control-Allow-Methods",
1683 | "key": "Access-Control-Allow-Methods",
1684 | "value": "",
1685 | "description": ""
1686 | },
1687 | {
1688 | "name": "Access-Control-Allow-Origin",
1689 | "key": "Access-Control-Allow-Origin",
1690 | "value": "",
1691 | "description": ""
1692 | },
1693 | {
1694 | "name": "Connection",
1695 | "key": "Connection",
1696 | "value": "keep-alive",
1697 | "description": ""
1698 | },
1699 | {
1700 | "name": "Content-Encoding",
1701 | "key": "Content-Encoding",
1702 | "value": "gzip",
1703 | "description": ""
1704 | },
1705 | {
1706 | "name": "Content-Length",
1707 | "key": "Content-Length",
1708 | "value": "46",
1709 | "description": ""
1710 | },
1711 | {
1712 | "name": "Content-Type",
1713 | "key": "Content-Type",
1714 | "value": "application/json; charset=utf-8",
1715 | "description": ""
1716 | },
1717 | {
1718 | "name": "Date",
1719 | "key": "Date",
1720 | "value": "Thu, 29 Oct 2015 06:16:00 GMT",
1721 | "description": ""
1722 | },
1723 | {
1724 | "name": "Server",
1725 | "key": "Server",
1726 | "value": "nginx/1.6.2",
1727 | "description": ""
1728 | },
1729 | {
1730 | "name": "Vary",
1731 | "key": "Vary",
1732 | "value": "Accept-Encoding",
1733 | "description": ""
1734 | },
1735 | {
1736 | "name": "X-Powered-By",
1737 | "key": "X-Powered-By",
1738 | "value": "Sails ",
1739 | "description": ""
1740 | }
1741 | ],
1742 | "cookies": [],
1743 | "mime": "",
1744 | "text": "{\"cookies\":{\"foo2\":\"bar\"}}",
1745 | "language": "javascript",
1746 | "rawDataType": "text",
1747 | "state": {
1748 | "size": "normal"
1749 | },
1750 | "previewType": "html",
1751 | "searchResultScrolledTo": "-1",
1752 | "version": null,
1753 | "requestObject": "\"4ac1e980-6990-fc1d-5f80-4e5cedce9812\"",
1754 | "createdAt": "2016-05-25T12:29:57.000Z",
1755 | "updatedAt": "2016-05-25T12:29:58.000Z",
1756 | "write": true
1757 | }
1758 | ],
1759 | "folder": "37368024-f6a8-0f70-85fc-7e876cde9e33"
1760 | },
1761 | {
1762 | "folder": "5d3595b3-5e8e-9e33-05ed-855c77298e4e",
1763 | "id": "da16c006-6293-c1fe-ea42-e9ba8a5e68b1",
1764 | "name": "Request Headers",
1765 | "dataMode": "params",
1766 | "data": [],
1767 | "rawModeData": null,
1768 | "descriptionFormat": null,
1769 | "description": "A `GET` request to this endpoint returns the list of all request headers as part of the response JSON.\nIn Postman, sending your own set of headers through the [Headers tab](https://www.getpostman.com/docs/requests#headers?source=echo-collection-app-onboarding) will reveal the headers as part of the response.",
1770 | "headers": "my-sample-header: Lorem ipsum dolor sit amet\n",
1771 | "method": "GET",
1772 | "pathVariables": {},
1773 | "url": "https://echo.getpostman.com/headers",
1774 | "preRequestScript": "",
1775 | "tests": "var responseJSON;\ntry {\n tests[\"Body contains headers\"] = responseBody.has(\"headers\");\n responseJSON = JSON.parse(responseBody);\n tests[\"Header contains host\"] = \"host\" in responseJSON.headers;\n tests[\"Header contains test parameter sent as part of request header\"] = \"my-sample-header\" in responseJSON.headers;\n}\ncatch (e) { }\n\n\n\n",
1776 | "currentHelper": "normal",
1777 | "helperAttributes": {},
1778 | "collectionId": "f695cab7-6878-eb55-7943-ad88e1ccfd65",
1779 | "responses": [
1780 | {
1781 | "owner": 0,
1782 | "lastUpdatedBy": "631643",
1783 | "lastRevision": 277278561,
1784 | "request": {
1785 | "url": "https://echo.getpostman.com/headers",
1786 | "headers": [
1787 | {
1788 | "key": "my-sample-header",
1789 | "value": "Lorem ipsum dolor sit amet",
1790 | "enabled": true
1791 | }
1792 | ],
1793 | "data": [],
1794 | "method": "GET",
1795 | "dataMode": "params"
1796 | },
1797 | "id": "881f141f-44c5-702f-211d-475360c6ccb3",
1798 | "name": "my-sample-header",
1799 | "status": "",
1800 | "responseCode": {
1801 | "code": 200,
1802 | "name": "OK"
1803 | },
1804 | "time": "460",
1805 | "headers": [
1806 | {
1807 | "name": "Access-Control-Allow-Credentials",
1808 | "key": "Access-Control-Allow-Credentials",
1809 | "value": "",
1810 | "description": ""
1811 | },
1812 | {
1813 | "name": "Access-Control-Allow-Headers",
1814 | "key": "Access-Control-Allow-Headers",
1815 | "value": "",
1816 | "description": ""
1817 | },
1818 | {
1819 | "name": "Access-Control-Allow-Methods",
1820 | "key": "Access-Control-Allow-Methods",
1821 | "value": "",
1822 | "description": ""
1823 | },
1824 | {
1825 | "name": "Access-Control-Allow-Origin",
1826 | "key": "Access-Control-Allow-Origin",
1827 | "value": "",
1828 | "description": ""
1829 | },
1830 | {
1831 | "name": "Connection",
1832 | "key": "Connection",
1833 | "value": "keep-alive",
1834 | "description": ""
1835 | },
1836 | {
1837 | "name": "Content-Encoding",
1838 | "key": "Content-Encoding",
1839 | "value": "gzip",
1840 | "description": ""
1841 | },
1842 | {
1843 | "name": "Content-Length",
1844 | "key": "Content-Length",
1845 | "value": "342",
1846 | "description": ""
1847 | },
1848 | {
1849 | "name": "Content-Type",
1850 | "key": "Content-Type",
1851 | "value": "application/json; charset=utf-8",
1852 | "description": ""
1853 | },
1854 | {
1855 | "name": "Date",
1856 | "key": "Date",
1857 | "value": "Thu, 31 Mar 2016 11:14:00 GMT",
1858 | "description": ""
1859 | },
1860 | {
1861 | "name": "Server",
1862 | "key": "Server",
1863 | "value": "nginx/1.6.2",
1864 | "description": ""
1865 | },
1866 | {
1867 | "name": "Vary",
1868 | "key": "Vary",
1869 | "value": "Accept-Encoding",
1870 | "description": ""
1871 | },
1872 | {
1873 | "name": "X-Powered-By",
1874 | "key": "X-Powered-By",
1875 | "value": "Sails ",
1876 | "description": ""
1877 | }
1878 | ],
1879 | "cookies": [
1880 | {
1881 | "domain": "echo.getpostman.com",
1882 | "hostOnly": true,
1883 | "httpOnly": true,
1884 | "name": "sails.sid",
1885 | "path": "/",
1886 | "secure": false,
1887 | "session": true,
1888 | "storeId": "0",
1889 | "value": "s%3A9stja5zKmIILxq9Jvtha7Lp9LIz1VIdK.Vp8MHC%2BEUJe4ICZPXn2JAoXaV2bTgtoQd%2B3XJLNr51Y"
1890 | }
1891 | ],
1892 | "mime": "",
1893 | "text": "{\"headers\":{\"host\":\"echo.getpostman.com\",\"accept\":\"*/*\",\"accept-encoding\":\"gzip, deflate, sdch\",\"accept-language\":\"en-US,en;q=0.8\",\"cache-control\":\"no-cache\",\"my-sample-header\":\"Lorem ipsum dolor sit amet\",\"postman-token\":\"3c8ea80b-f599-fba6-e0b4-a0910440e7b6\",\"user-agent\":\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.110 Safari/537.36\",\"x-forwarded-port\":\"443\",\"x-forwarded-proto\":\"https\"}}",
1894 | "language": "javascript",
1895 | "rawDataType": "text",
1896 | "state": {
1897 | "size": "normal"
1898 | },
1899 | "previewType": "html",
1900 | "searchResultScrolledTo": "-1",
1901 | "version": null,
1902 | "requestObject": "{\"url\":\"https://echo.getpostman.com/headers\",\"headers\":[{\"key\":\"my-sample-header\",\"value\":\"Lorem ipsum dolor sit amet\",\"enabled\":true}],\"data\":[],\"method\":\"GET\",\"dataMode\":\"params\"}",
1903 | "createdAt": "2016-05-25T12:29:57.000Z",
1904 | "updatedAt": "2016-05-25T12:29:58.000Z",
1905 | "write": true
1906 | }
1907 | ]
1908 | },
1909 | {
1910 | "folder": "5d3595b3-5e8e-9e33-05ed-855c77298e4e",
1911 | "id": "e50f9111-3a52-a325-47f1-fc702bea1fff",
1912 | "name": "Response Headers",
1913 | "dataMode": "params",
1914 | "data": [],
1915 | "rawModeData": null,
1916 | "descriptionFormat": null,
1917 | "description": "This endpoint causes the server to send custom set of response headers. Providing header values as part of the URL parameters of a `GET` request to this endpoint returns the same as part of response header.\n\nTo send your own set of headers, simply add or replace the the URL parameters with your own set.",
1918 | "headers": "",
1919 | "method": "GET",
1920 | "pathVariables": {},
1921 | "url": "https://echo.getpostman.com/response-headers?Content-Type=text/html&test=response_headers",
1922 | "preRequestScript": "",
1923 | "tests": "tests[\"Body contains Content-Type\"] = responseBody.has(\"Content-Type\");\ntests[\"response headers have key sent as part of request\"] = (postman.getResponseHeader('test') == 'response_headers')",
1924 | "currentHelper": "normal",
1925 | "helperAttributes": {},
1926 | "collectionId": "f695cab7-6878-eb55-7943-ad88e1ccfd65",
1927 | "responses": [
1928 | {
1929 | "owner": 0,
1930 | "lastUpdatedBy": "631643",
1931 | "lastRevision": 277278570,
1932 | "request": {
1933 | "url": "https://echo.getpostman.com/response-headers?Content-Type=text/html&test=response_headers",
1934 | "headers": [],
1935 | "data": [],
1936 | "method": "GET",
1937 | "dataMode": "params"
1938 | },
1939 | "id": "85a7208f-3c37-f297-9772-81b97d28dae0",
1940 | "name": "Response headers",
1941 | "status": "",
1942 | "responseCode": {
1943 | "code": 200,
1944 | "name": "OK"
1945 | },
1946 | "time": "568",
1947 | "headers": [
1948 | {
1949 | "name": "Access-Control-Allow-Credentials",
1950 | "key": "Access-Control-Allow-Credentials",
1951 | "value": "",
1952 | "description": ""
1953 | },
1954 | {
1955 | "name": "Access-Control-Allow-Headers",
1956 | "key": "Access-Control-Allow-Headers",
1957 | "value": "",
1958 | "description": ""
1959 | },
1960 | {
1961 | "name": "Access-Control-Allow-Methods",
1962 | "key": "Access-Control-Allow-Methods",
1963 | "value": "",
1964 | "description": ""
1965 | },
1966 | {
1967 | "name": "Access-Control-Allow-Origin",
1968 | "key": "Access-Control-Allow-Origin",
1969 | "value": "",
1970 | "description": ""
1971 | },
1972 | {
1973 | "name": "Connection",
1974 | "key": "Connection",
1975 | "value": "keep-alive",
1976 | "description": ""
1977 | },
1978 | {
1979 | "name": "Content-Encoding",
1980 | "key": "Content-Encoding",
1981 | "value": "gzip",
1982 | "description": ""
1983 | },
1984 | {
1985 | "name": "Content-Length",
1986 | "key": "Content-Length",
1987 | "value": "71",
1988 | "description": ""
1989 | },
1990 | {
1991 | "name": "Content-Type",
1992 | "key": "Content-Type",
1993 | "value": "text/html; charset=utf-8",
1994 | "description": ""
1995 | },
1996 | {
1997 | "name": "Date",
1998 | "key": "Date",
1999 | "value": "Thu, 31 Mar 2016 11:14:18 GMT",
2000 | "description": ""
2001 | },
2002 | {
2003 | "name": "Server",
2004 | "key": "Server",
2005 | "value": "nginx/1.6.2",
2006 | "description": ""
2007 | },
2008 | {
2009 | "name": "Vary",
2010 | "key": "Vary",
2011 | "value": "Accept-Encoding",
2012 | "description": ""
2013 | },
2014 | {
2015 | "name": "X-Powered-By",
2016 | "key": "X-Powered-By",
2017 | "value": "Sails ",
2018 | "description": ""
2019 | },
2020 | {
2021 | "name": "test",
2022 | "key": "test",
2023 | "value": "response_headers",
2024 | "description": ""
2025 | }
2026 | ],
2027 | "cookies": [
2028 | {
2029 | "domain": "echo.getpostman.com",
2030 | "hostOnly": true,
2031 | "httpOnly": true,
2032 | "name": "sails.sid",
2033 | "path": "/",
2034 | "secure": false,
2035 | "session": true,
2036 | "storeId": "0",
2037 | "value": "s%3A9stja5zKmIILxq9Jvtha7Lp9LIz1VIdK.Vp8MHC%2BEUJe4ICZPXn2JAoXaV2bTgtoQd%2B3XJLNr51Y"
2038 | }
2039 | ],
2040 | "mime": "",
2041 | "text": "{\"Content-Type\":\"text/html\",\"test\":\"response_headers\"}",
2042 | "language": "html",
2043 | "rawDataType": "text",
2044 | "state": {
2045 | "size": "normal"
2046 | },
2047 | "previewType": "html",
2048 | "searchResultScrolledTo": "-1",
2049 | "version": null,
2050 | "requestObject": "{\"url\":\"https://echo.getpostman.com/response-headers?Content-Type=text/html&test=response_headers\",\"headers\":[],\"data\":[],\"method\":\"GET\",\"dataMode\":\"params\"}",
2051 | "createdAt": "2016-05-25T12:29:58.000Z",
2052 | "updatedAt": "2016-05-25T12:29:58.000Z",
2053 | "write": true
2054 | }
2055 | ]
2056 | },
2057 | {
2058 | "folder": "930f54b4-c5cd-2363-7cf5-b9022d3c0aae",
2059 | "id": "fd961ad0-ab24-68d8-4be5-573e8585d526",
2060 | "name": "GZip Compressed Response",
2061 | "dataMode": "params",
2062 | "data": [],
2063 | "rawModeData": null,
2064 | "descriptionFormat": null,
2065 | "description": "This endpoint returns the response using [gzip compression algoritm](https://en.wikipedia.org/wiki/Gzip).\nThe uncompressed response is a JSON string containing the details of the request sent by the client. For this endpoint to work, one should request with `Accept-encoding` header containing `gzip` as part of its value. Postman supports gzip, deflate and SDCH decoding and automatically sends them as part of the request.\n\nHTTP Compression allows the server to send responses in a compressed format, which is uncompressed by the client before processing. This reduces network bandwidth consumption at the cost of increase in CPU usage.\nTo know more about this, refer the [HTTP Compression](https://en.wikipedia.org/wiki/HTTP_compression) wikipedia article.",
2066 | "headers": "",
2067 | "method": "GET",
2068 | "pathVariables": {},
2069 | "url": "https://echo.getpostman.com/gzip",
2070 | "preRequestScript": "",
2071 | "tests": "try {\n var data = JSON.parse(responseBody);\n tests[\"Body contains gzipped\"] = responseBody.has(\"gzipped\");\n tests[\"Body contains headers\"] = responseBody.has(\"headers\");\n tests[\"Body contains method\"] = responseBody.has(\"method\");\n}\ncatch(e) {\n console.log('Cannot parse response,probably not a JSON');\n}\ntests[\"response code is 200\"] = responseCode.code === 200;",
2072 | "currentHelper": "normal",
2073 | "helperAttributes": {},
2074 | "collectionId": "f695cab7-6878-eb55-7943-ad88e1ccfd65"
2075 | }
2076 | ]
2077 | }
--------------------------------------------------------------------------------