% man curl...--resolve <[+]host:port:addr[,addr]...>Provide a custom address for a specific host and port pair. Using this, you can make the curl requests(s) use a specifiedaddress and prevent the otherwise normally resolved address to be used. Consider it a sort of /etc/hosts alternativeprovided on the command line. The port number should be the number used for the specific protocol the host will be used for.It means you need several entries if you want to provide address for the same host but different ports.By specifying '*' as host you can tell curl to resolve any host and specific port pair to the specified address. Wildcard isresolved last so any --resolve with a specific host and port will be used first.The provided address set by this option will be used even if --ipv4 or --ipv6 is set to make curl use another IP version.By prefixing the host with a '+' you can make the entry time out after curl's default timeout (1 minute). Note that thiswill only make sense for long running parallel transfers with a lot of files. In such cases, if this option is used curlwill try to resolve the host as it normally would once the timeout has expired.Support for providing the IP address within [brackets] was added in 7.57.0.Support for providing multiple IP addresses per entry was added in 7.59.0.Support for resolving with wildcard was added in 7.64.0.Support for the '+' prefix was was added in 7.75.0.This option can be used many times to add many host names to resolve.Example:curl --resolve example.com:443:127.0.0.1 https://example.comSee also --connect-to and --alt-svc.
2022年8月25日 星期四
使用 curl 指定 Server IP 檢驗 SSL 憑證 (SKIP DNS LOOKUP)
2020年11月6日 星期五
[Linux] 使用 uClibc-ng 製作 x86_64 開發測試環境,以編譯 curl / libcurl 為例 @ Ubuntu 20.04
由於硬體要限縮資源,這時會把常見的 glibc 換成 uclibc 節省空間,而過程包括要建置 toolchain 等等。由於部分程式在 embedded linux 運作不如預期,大家擔心可能是 uclibc 產生的問題,就出現在 x86_64 運行 uclibc 作檢驗的念頭
實作上也是要建置 x86_64 的 toolchain 出來,此例就用 curl / libcurl 為例。此篇工作記錄參考 编译工具链制作-x86_64-linux-uclibc 文章,建議先拜讀這篇,裡頭編譯參數的項目都有說明,佛心啊。此處筆記是設法把開發環境都用最新環境,包括:
- Ubuntu 20.04.1 LTS server
- uClibc-ng-1.0.36
- binutils-2.35
- gcc-9.3.0
- mpfr-4.1.0
- mpc-1.2.1
- gmp-6.1.2
- linux-2.6.39
而後面編譯 curl 採用以下資源:
- tiny-curl-7.72.0
- zlib-1.2.11
- openssl-1.1.1h
採用 gcc-9.3.0 的主因是 ubuntu 20.04 預設 apt install gcc 就是 9.3 版。以下連續動作:
$ wget https://ftp.gnu.org/gnu/binutils/binutils-2.35.tar.gz
$ wget https://ftp.gnu.org/gnu/gcc/gcc-9.3.0/gcc-9.3.0.tar.gz
$ wget https://ftp.gnu.org/gnu/gmp/gmp-6.1.2.tar.bz2
$ wget https://ftp.gnu.org/gnu/mpc/mpc-1.2.1.tar.gz
$ wget https://ftp.gnu.org/gnu/mpfr/mpfr-4.1.0.tar.gz
$ wget http://ftp.ntu.edu.tw/linux/kernel/v2.6/linux-2.6.39.tar.gz
$ wget https://downloads.uclibc-ng.org/releases/1.0.36/uClibc-ng-1.0.36.tar.gz
並全在 user 家目錄解壓縮,解壓縮後把 open source 包都移到 resource 目錄中保存:
user@buildserver:~$ tree -L 1
.
├── binutils-2.35
├── gcc-9.3.0
├── gmp-6.1.2
├── linux-2.6.39
├── mpc-1.2.1
├── mpfr-4.1.0
├── resource
└── uClibc-ng-1.0.36
安裝一些工具:
$ sudo apt install make cmake gcc g++ libncurses-dev libncurses5-dev
$ gcc -v
...
Thread model: posix
gcc version 9.3.0 (Ubuntu 9.3.0-17ubuntu1~20.04)
$ g++ -v
...
Thread model: posix
gcc version 9.3.0 (Ubuntu 9.3.0-17ubuntu1~20.04)
$ make -v
GNU Make 4.2.1
Built for x86_64-pc-linux-gnu
$ cmake --version
cmake version 3.16.3
建置環境變數,預計都安裝在家目錄的 tarball 裡,此例就是 /home/user/tarball:
$ cat ~/uclibc-init.sh
export ARCH=x86
export TARGET=x86_64-linux-uclibc
export PREFIX=/home/user/tarball
export TARGET_PREFIX=$PREFIX/$TARGET
export PATH=$PREFIX/bin:$PATH
$ source ~/uclibc-init.sh
$ mkdir -p $TARGET_PREFIX
編譯 binutils 環境:
$ cd binutils-2.35 && mkdir -p $TARGET && cd $TARGET
$ ../configure \
--prefix=$PREFIX \
--with-lib-path=$PREFIX/lib:$PREFIX/lib64 \
--disable-multilib \
--disable-werror \
--disable-nls \
--enable-gold \
--target=$TARGET
$ make && make install
$ x86_64-linux-uclibc-ld --verbose | grep SEARCH
SEARCH_DIR("/home/user/tarball/x86_64-linux-uclibc/lib64"); SEARCH_DIR("/home/user/tarball/lib"); SEARCH_DIR("/home/user/tarball/lib64"); SEARCH_DIR("/home/user/tarball/x86_64-linux-uclibc/lib");
這邊增加 --enable-gold 用於 gcc-9.3 的編譯時會踩到的需求,通常就是缺一些 header files 就是要找找看躲在 binutils, uclibc 等等
安置 linux header files:
$ linux-2.6.39/
$ make ARCH=$ARCH INSTALL_HDR_PATH=$TARGET_PREFIX headers_install
編譯跨平台 gcc 工具:
$ cd gcc-9.3.0/
$ ln -s ../mpc-1.2.1/ mpc
$ ln -s ../mpfr-4.1.0/ mpfr
$ ln -s ../gmp-6.1.2/ gmp
$ mkdir -p $TARGET && cd $TARGET
$ ../configure \
--prefix=$PREFIX \
--with-sysroot=$PREFIX \
--with-local-prefix=$PREFIX \
--with-native-system-header-dir=/$TARGET/include \
--enable-languages=c,c++ \
--enable-linker-build-id \
--disable-multilib \
--disable-werror \
--without-headers \
--with-newlib \
--disable-shared \
--disable-nls \
--target=$TARGET
$ make all-gcc
$ make install-gcc安置 uclibc 相關檔案們(startfiles/headers):
$ cd uClibc-ng-1.0.36
$ make menuconfig
Target Architecture
--> x86_64
Target Architecture Features and Options
--> [*] Enable full C99 math library support
--> [*] Enable C99 Floating-point environment
--> Linux kernel header location (/home/user/tarball/x86_64-linux-uclibc/include)
General Library Settings
--> [*] Dynamic linker stand-alone mode support
--> Thread support (Native POSIX Threading (NPTL))
--> [*] utmpx based support for tracking login/logouts to/from the system
--> [*] utmp support (XPG2 compat, SVr4 compat)
--> [*] Enable SuSv3 LEGACY functions
--> [*] Enable SuSv3 LEGACY macros
--> [*] Enable SuSv4 or obsolescent functions
Advanced Library Settings
--> [*] Enable SVr4 deprecated functions
Networking Support
--> [*] IP version 6 support
--> [*] Use netlink to query interfaces
--> [*] Support the AI_ADDRCONFIG flag
--> [*] DNS resolver functions
String and Stdio Support
--> [*] Wide Charater Support
Big and Tall
--> [*] Support the wordexp() interface
Libray Installation Options
--> uClibc runtime library directory(/home/user/tarball/x86_64-linux-uclibc)
--> uClibc development envirment directory(/home/user/tarball/x86_64-linux-uclibc)
Development/debugging options
--> Cross-compiling toolchain prefix (x86_64-linux-uclibc-)
--> (-D__NR_setns -D__NR_syncfs) Extra CFLAGS
$ make startfiles
$ PREFIX="" make install_startfiles
$ PREFIX="" make install_headers
其中我開啟了不少項目都是後邊在編譯 gcc-9.3 和 curl 會用到的項目,像是缺 ifaddrs.h 而開啟 Support the AI_ADDRCONFIG flag 又相依要開啟 Use netlink to query interfaces 選項等等。過程常見的都是編譯期間缺 header files 而反覆在 uclibc 開啟資源,可以把缺的 header files 在 uclibc 中靠 find 或 grep 搜尋
繼續編譯跨平台 libgcc:
$ cd ~/gcc-9.3.0/$TARGET
$ make all-target-libgcc
$ make install-target-libgcc
編譯和安裝 uclibc :
$ cd ~/uClibc-ng-1.0.36/
$ make
$ PREFIX="" make install
最後一次 gcc 編譯:
$ cd ~/gcc-9.3.0/$TARGET
$ ../configure \
--prefix=$PREFIX \
--with-sysroot=/ \
--with-local-prefix=$PREFIX \
--with-native-system-header-dir=$TARGET_PREFIX/include \
--enable-languages=c,c++ \
--enable-linker-build-id \
--disable-libsanitizer \
--disable-multilib \
--disable-werror \
--disable-nls \
--target=$TARGET
$ make all
$ make install
如此,就可以有基本的環境運行了,例如編譯 main.c:
$ cat main.c
#include <stdio.h>
int main(int argc, char *argv[]) {
printf("Hello\n");
return 0;
}
$ x86_64-linux-uclibc-gcc main.c
$ ./a.out
-bash: ./a.out: No such file or directory
$ file a.out
a.out: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib/ld64-uClibc.so.0, BuildID[sha1]=c243334b7550adf7ef5342019c444d6762da738b, not stripped
$ ~/tarball/x86_64-linux-uclibc/lib/ld64-uClibc-1.0.36.so --library-path /home/user/tarball/x86_64-linux-uclibc/lib/:/home/user/tarball/x86_64-linux-uclibc/lib64:/home/user/tarball/lib ./a.out
Hello
緊接著編譯 curl 來用,因為他相依 openssl, libssh2, zlib ,所以過程要先把這些函示庫都編好:
$ wget https://zlib.net/zlib-1.2.11.tar.gz
$ tar -xvf zlib-1.2.11.tar.gz && cd ~/zlib-1.2.11
$ CC=x86_64-linux-uclibc-gcc CXX=x86_64-linux-uclibc-g++ ./configure --prefix=$PREFIX
$ make && make install
$ wget https://www.libssh2.org/download/libssh2-1.9.0.tar.gz
$ tar -xvf libssh2-1.9.0.tar.gz && cd libssh2-1.9.0
$ CC=x86_64-linux-uclibc-gcc CXX=x86_64-linux-uclibc-g++ ./configure --prefix=$PREFIX --host x86_64-linux-uclibc
$ make && make install
$ wget https://www.openssl.org/source/openssl-1.1.1h.tar.gz
$ tar -xvf openssl-1.1.1h.tar.gz && cd ~/openssl-1.1.1h
$ CC=x86_64-linux-uclibc-gcc CXX=x86_64-linux-uclibc-g++ ./config --prefix=$PREFIX -latomic no-threads no-shared no-rc5 enable-camellia enable-mdc2 no-tests no-fuzz-libfuzzer no-fuzz-afl zlib
$ make && make install
$ wget https://curl.haxx.se/tiny/tiny-curl-7.72.0.tar.gz
$ tar -xvf tiny-curl-7.72.0.tar.gz && cd tiny-curl-7.72.0
$ mkdir build && cd build
$ CC=x86_64-linux-uclibc-gcc CXX=x86_64-linux-uclibc-gc++ cmake .. -DCMAKE_PREFIX_PATH=~/tarball -DCMAKE_INSTALL_PREFIX=~/tarball
$ make && make install
$ /home/user/tarball/bin/curl
-bash: /home/user/tarball/bin/curl: No such file or directory
$ ~/tarball/x86_64-linux-uclibc/lib/ld64-uClibc-1.0.36.so --library-path /home/user/tarball/x86_64-linux-uclibc/lib/:/home/user/tarball/x86_64-linux-uclibc/lib64:/home/user/tarball/lib /home/user/tarball/bin/curl --version
curl 7.72.0 (Linux) libcurl/7.72.0 OpenSSL/1.1.1h zlib/1.2.11 libssh2/1.9.0
Release-Date: 2020-08-27
Protocols: dict file ftp ftps gopher http https imap imaps pop3 pop3s rtsp scp sftp smb smbs smtp smtps telnet tftp
Features: AsynchDNS HTTPS-proxy IPv6 Largefile libz NTLM SSL UnixSockets
收工!
2020年3月17日 星期二
使用 curl 仿 DLNA controller 指令播放影片: DLNA protocol + SOAP protocol
裝置搜尋:
$ python dlnap.py
No compatible devices found.
$ python dlnap.py
Discovered devices:
[a] Name1 @ 192.168.1.2
[a] Name2 @ 192.168.1.3
播放影片:
$ python dlnap.py -d Name1 --play http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4
No compatible devices found.
$ python dlnap.py -d Name1 --play http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4
Name1 @ 192.168.1.2
POST AVTransport/control HTTP/1.1
User-Agent: dlnap.py/0.15
Accept: */*
Content-Type: text/xml; charset="utf-8"
HOST: 192.168.1.2:60099
Content-Length: 558
SOAPACTION: "urn:schemas-upnp-org:service:AVTransport:1#SetAVTransportURI"
Connection: close
<?xml version="1.0" encoding="utf-8"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<s:Body>
<u:SetAVTransportURI xmlns:u="urn:schemas-upnp-org:service:AVTransport:1">
<InstanceID>0</InstanceID><CurrentURIMetaData></CurrentURIMetaData><CurrentURI>http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4</CurrentURI>
</u:SetAVTransportURI>
</s:Body>
</s:Envelope>
POST AVTransport/control HTTP/1.1
User-Agent: dlnap.py/0.15
Accept: */*
Content-Type: text/xml; charset="utf-8"
HOST: 192.168.1.2:60099
Content-Length: 401
SOAPACTION: "urn:schemas-upnp-org:service:AVTransport:1#Play"
Connection: close
<?xml version="1.0" encoding="utf-8"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<s:Body>
<u:Play xmlns:u="urn:schemas-upnp-org:service:AVTransport:1">
<InstanceID>0</InstanceID><Speed>1</Speed>
</u:Play>
</s:Body>
</s:Envelope>
可惜的,在測試播放影片時總不太順利,推論應當是兩個指令太快,改用 curl 指令測試就很正常:
1. 先設定影片
$ cat SetAVTransportURI.record
<?xml version="1.0" encoding="utf-8"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<s:Body>
<u:SetAVTransportURI xmlns:u="urn:schemas-upnp-org:service:AVTransport:1">
<InstanceID>0</InstanceID>
<CurrentURIMetaData></CurrentURIMetaData>
<CurrentURI>http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4</CurrentURI>
</u:SetAVTransportURI>
</s:Body>
</s:Envelope>
$ curl -v -X POST --data @SetAVTransportURI.record -H 'SOAPACTION: "urn:schemas-upnp-org:service:AVTransport:1#SetAVTransportURI"' -H 'Content-Type: text/xml; charset="utf-8"' http://192.168.1.2:60099/AVTransport/control
Note: Unnecessary use of -X or --request, POST is already inferred.
* Trying 192.168.1.2:60099...
* TCP_NODELAY set
* Connected to 192.168.1.2 (192.168.1.2) port 60099 (#0)
> POST /AVTransport/control HTTP/1.1
> Host: 192.168.1.2:60099
> User-Agent: curl/7.68.0
> Accept: */*
> SOAPACTION: "urn:schemas-upnp-org:service:AVTransport:1#SetAVTransportURI"
> Content-Type: text/xml; charset="utf-8"
> Content-Length: 476
>
* upload completely sent off: 476 out of 476 bytes
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< EXT:
< CONTENT-TYPE: text/xml; charset="utf-8"
< SERVER: POSIX, UPnP/1.0, Intel MicroStack/1.0.2777
< Content-Length: 336
<
<?xml version="1.0" encoding="utf-8"?>
<s:Envelope s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<u:SetAVTransportURIResponse xmlns:u="urn:schemas-upnp-org:service:AVTransport:1">
</u:SetAVTransportURIResponse>
</s:Body>
* Connection #0 to host 192.168.1.2 left intact
</s:Envelope>
2. 呼叫播放
$ cat Play.record
<?xml version="1.0" encoding="utf-8"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<s:Body>
<u:Play xmlns:u="urn:schemas-upnp-org:service:AVTransport:1">
<InstanceID>0</InstanceID>
<Speed>1</Speed>
</u:Play>
</s:Body>
</s:Envelope>
$ curl -v -X POST --data @Play.record -H 'SOAPACTION: "urn:schemas-upnp-org:service:AVTransport:1#Play"' -H 'Content-Type: text/xml; charset="utf-8"' http://192.168.1.2:60099/AVTransport/control
Note: Unnecessary use of -X or --request, POST is already inferred.
* Trying 192.168.1.2:60099...
* TCP_NODELAY set
* Connected to 192.168.1.2 (192.168.1.2) port 60099 (#0)
> POST /AVTransport/control HTTP/1.1
> Host: 192.168.1.2:60099
> User-Agent: curl/7.68.0
> Accept: */*
> SOAPACTION: "urn:schemas-upnp-org:service:AVTransport:1#Play"
> Content-Type: text/xml; charset="utf-8"
> Content-Length: 316
>
* upload completely sent off: 316 out of 316 bytes
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< EXT:
< CONTENT-TYPE: text/xml; charset="utf-8"
< SERVER: POSIX, UPnP/1.0, Intel MicroStack/1.0.2777
< Content-Length: 310
<
<?xml version="1.0" encoding="utf-8"?>
<s:Envelope s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<u:PlayResponse xmlns:u="urn:schemas-upnp-org:service:AVTransport:1">
</u:PlayResponse>
</s:Body>
* Connection #0 to host 192.168.1.2 left intact
</s:Envelope>
2019年8月22日 星期四
[macOS] 使用 cURL command 上傳檔案且修改 Content-Disposition filename 欄位資訊
而透過 cURL 上傳檔案,通常是用以下簡單的指定就完成:
$ curl -F "file=@/tmp/sample.txt" http://192.168.1.1/cgi-bin/upload.cgi
但如果細看表單內容物時,產出的結果:
POST /cgi-bin/upload.cgi HTTP/1.1
Host: 192.168.1.1
Content-Type: multipart/form-data
Content-Length: ##
----------########
Content-Disposition: form-data; name="file";
filename="sample.txt"
...
這時,有些 CGI 開發上會直接拿上述 filename 參數資訊來用,寫不好就會產生跳脫問題,如:
Content-Disposition: form-data; name="file";
filename="../etc/sample.txt"
若底層是直接用 sprintf(des_filepath, "/tmp/%s", filename); 就會有機會逃脫去覆蓋掉東西。幸運的是 embedded linux 大多會設定檔案系統是 Read-only file system 來保護 :P 若是用 PHP 時,大多都靠 basename 來保護了。
最後,補上靠 curl 串改 filename 的招數:
$ curl -F "file=@/tmp/sample.txt; filename=../etc/sample.txt" http://192.168.1.1/cgi-bin/upload.cgi
2015年5月19日 星期二
透過 jq, sed, grep 從 wikipedia api 取出台灣地區鄉鎮市區列表 @ Ubuntu 14.04
http://zh.wikipedia.org/wiki/%E4%B8%AD%E8%8F%AF%E6%B0%91%E5%9C%8B%E8%87%BA%E7%81%A3%E5%9C%B0%E5%8D%80%E9%84%89%E9%8E%AE%E5%B8%82%E5%8D%80%E5%88%97%E8%A1%A8
接著想抓個鄉鎮對應表,就想起 wiki api:
http://zh.wikipedia.org/w/api.php?action=query&titles=%E4%B8%AD%E8%8F%AF%E6%B0%91%E5%9C%8B%E8%87%BA%E7%81%A3%E5%9C%B0%E5%8D%80%E9%84%89%E9%8E%AE%E5%B8%82%E5%8D%80%E5%88%97%E8%A1%A8&prop=revisions&rvprop=content&format=json
接著,再搭配 jq、sed、grep 縮一下資料量:
$ curl 'http://zh.wikipedia.org/w/api.php?action=query&titles=%E4%B8%AD%E8%8F%AF%E6%B0%91%E5%9C%8B%E8%87%BA%E7%81%A3%E5%9C%B0%E5%8D%80%E9%84%89%E9%8E%AE%E5%B8%82%E5%8D%80%E5%88%97%E8%A1%A8&prop=revisions&rvprop=content&format=json' | jq '.query.pages[].revisions[0]|to_entries[0].value' | sed 's/\\n/\n/g' | grep -P '<small>(.*)</small> \[\[(.*)\]\]' -o | sed 's/<small>\(.*\)<\/small> \[\[\(.*\)\]\]/\1\t\2/g' | sed 's/\(.*\)\t\(.*\)|\(.*\)/\1\t\3/g'
成果:
2014年11月25日 星期二
[PHP] 使用 CodeIgniter 和 codeigniter-restserver 建立 RESTful API 以及測試方式 @ Ubuntu 14.04
- Ubuntu 14.04 64 Bit (lsb_release -a)
- PHP 5.5.9 (php -v)
- CodeIgniter 2.2.0 (echo CI_VERSION)
接著,透過 github.com/chriskacerguis/codeigniter-restserver 擴充 CodeIgniter:
$ wget https://raw.githubusercontent.com/chriskacerguis/codeigniter-restserver/master/application/config/rest.php -O /path/ci_proj/application/config/rest.php
$ wget https://raw.githubusercontent.com/chriskacerguis/codeigniter-restserver/master/application/libraries/Format.php -O /path/ci_proj/application/libraries/Format.php
$ wget https://raw.githubusercontent.com/chriskacerguis/codeigniter-restserver/master/application/libraries/REST_Controller.php -O /path/ci_proj/application/libraries/REST_Controller.php
接著,請確認 application/config/rest.php 設定:
$config[rest_default_format] = 'json'; // 預設為 xml
之後,就可以撰寫簡單的 RESTful API 啦:
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
require(APPPATH.'/libraries/REST_Controller.php');
class Item extends REST_Controller {
public function index_get() {
$this->list_get();
}
public function index_post() {
$this->add_post();
}
public function index_put() {
$this->update_put();
}
public function index_delete() {
$this->delete_delte();
}
public function list_get() {
echo "list";
}
public function add_post() {
echo "create";
}
public function update_put() {
echo "put";
}
public function remove_delete() {
echo "remove";
}
}
測試方式:
取得清單(GET)
$ curl -X GET http://localhost/ci_proj/item/list
$ curl -X GET http://localhost/ci_proj/item/
新增資料(POST)
$ curl -X POST http://localhost/ci_proj/item/add
$ curl -X POST http://localhost/ci_proj/item/
更新資料(PUT)
$ curl -X PUT http://localhost/ci_proj/item/update
$ curl -X PUT http://localhost/ci_proj/item/
刪除資料(DELETE)
$ curl -X DELETE http://localhost/ci_proj/item/delete
$ curl -X DELETE http://localhost/ci_proj/item/
也可以用 wget --method GET/POST/PUT/DELETE 等進行測試。
至於 RESTful 常見的 HTTP STATUS CODE,可以參考 Using HTTP Methods for RESTful Services
例如:
取得清單成功回應 200 OK,失敗則為 404 NOT FOUND;新增資料成功 200 OK 或是 201 LOCATION 到新增項目的 URI,失敗為 404 NOT FOUND;更新資料成功為 200 OK,失敗為 404 NOT FOUND;刪除資料成功為 200 OK,失敗為 404 NOT FOUND。
接著,是設計每個 GET, POST, PUT, DELETE API 細節,可以分別使用 $this->get('param')、$this->post('param')、$this->put('param') 和 $this->delete('param') 取得對應資料,而回應時,需要的 HTTP Status Code 可以使用:
$this->response( array('status' => true), 200);
$this->response( array('status' => false, 'error' => 'error message'), 400);
$this->response( array('status' => false, 'error' => 'error message'), 404);
若要 debug 的話,大概可以用:
$this->response( array('status' => true, 'get' => $this->get(), 'post' => $this->post(), 'put' => $this->put(), 'delete' => $this->delete() ), 200);
搭配 curl -i -X GET|POST|PUT|DELETE -d 'key=value' 方式進行,除了可以看到 HTTP Response code 外,也能看到 get, post, put, delete 各種參數資訊:
$ curl -i -X DELETE -d "haha=hehe" CGI
HTTP/1.1 200 OK
Server: Apache/2.4.7 (Ubuntu)
X-Powered-By: PHP/5.5.9-1ubuntu4.5
Content-Length: 68
Content-Type: application/json; charset=utf-8
{"status":true,"get":[],"post":[],"put":[],"delete":{"haha":"hehe"}}
2014年6月27日 星期五
[PHP] 使用 CURL 測試 Remote Resource Availability @ Ubuntu 14.04
<?php
function checkRemoteResourceAvailability($target_url) {
$ch = curl_init($target_url);
curl_setopt($ch, CURLOPT_NOBODY, true);
$status = curl_exec($ch) !== false && curl_getinfo($ch, CURLINFO_HTTP_CODE) == 200;
curl_close($ch);
return $status;
}
echo checkRemoteResourceAvailability('http://tw.yahoo.com/favicon.ico') ? "ok" : "not available";