Skip to content

Commit

Permalink
upload dependencies, restclient
Browse files Browse the repository at this point in the history
  • Loading branch information
dieguich committed Nov 11, 2013
1 parent 924f9cc commit 4f1fd6b
Show file tree
Hide file tree
Showing 8 changed files with 994 additions and 0 deletions.
158 changes: 158 additions & 0 deletions dependencies/restclient/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
# RestClient for Arduino

HTTP Request library for Arduino and the Ethernet shield.

# Install

Clone (or download and unzip) the repository to `~/Documents/Arduino/libraries`
where `~/Documents/Arduino` is your sketchbook directory.

> cd ~/Documents/Arduino
> mkdir libraries
> cd libraries
> git clone https://github.com/csquared/arduino-restclient.git RestClient

# Usage

### Include

You need to have the `Ethernet` library already included.

```c++
#include <Ethernet.h>
#include <SPI.h>
#include "RestClient.h"
```

### RestClient(host/ip, [port])

Constructor to create an RestClient object to make requests against.

Use domain name and default to port 80:
```c++
RestClient client = RestClient("arduino-http-lib-test.herokuapp.com");
```

Use a local IP and an explicit port:
```c++
RestClient client = RestClient("192.168.1.50",5000);
```

### dhcp()

Sets up `EthernetClient` with a mac address of `DEADBEEFFEED`

```c++
client.dhcp()
```

Note: you can have multiple RestClient objects but only need to call
this once.

Note: if you have multiple Arduinos on the same network, you'll need
to give each one a different mac address.

### begin(byte mac[])

It just wraps the `EthernetClient` call to `begin` and DHCPs.
Use this if you need to explicitly set the mac address.

```c++
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
if (client.begin(mac) == 0) {
Serial.println("Failed to configure Ethernet using DHCP");
}
```
### Manual Ethernet Setup
You can skip the above methods and just configure the EthernetClient yourself:
```c++
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
//the IP address for the shield:
byte ip[] = { 192, 168, 2, 11 };
Ethernet.begin(mac,ip);
```

```c++
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
Ethernet.begin(mac);
```
This is especially useful for debugging network connection issues.
## RESTful methods
All methods return an HTTP status code or 0 if there was an error.
### `get(const char* path)`
### `get(const char* path, String* response)`
Start making requests!
```c++
int statusCode = client.get("/"));
```

Pass in a string *by reference* for the response:
```
String response = "";
int statusCode = client.get("/", &response);
```

### post(const char* path, const char* body)
### post(const char* path, String* response)
### post(const char* path, const char* body, String* response)

```
String response = "";
int statusCode = client.post("/", &response);
statusCode = client.post("/", "foo=bar");
response = "";
statusCode = client.post("/", "foo=bar", &response);
```

### put(const char* path, const char* body)
### put(const char* path, String* response)
### put(const char* path, const char* body, String* response)

```
String response = "";
int statusCode = client.put("/", &response);
statusCode = client.put("/", "foo=bar");
response = "";
statusCode = client.put("/", "foo=bar", &response);
```

### del(const char* path)
### del(const char* path, const char* body)
### del(const char* path, String* response)
### del(const char* path, const char* body, String* response)

```
String response = "";
int statusCode = client.del("/", &response);
```

## Full Example

I test every way of calling the library (against a public heroku app)[https://github.com/csquared/arduino-http-test].

You can find the file in File->Examples->RestClient->full_test_suite

## Debug Mode

If you're having trouble, you can always open `RestClient.cpp` and throw at the top:

```c++
#define HTTP_DEBUG
```

Everything happening in the client will get printed to the Serial port.

# Thanks

[ricardochimal](https://github.com/ricardochimal) For all his c++ help. Couldn't have done this without you!

[theycallmeswift](https://github.com/theycallmeswift) Helping incept and debug v1.0
239 changes: 239 additions & 0 deletions dependencies/restclient/RestClient.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,239 @@
#include "RestClient.h"

#ifdef HTTP_DEBUG
#define HTTP_DEBUG_PRINT(string) (Serial.print(string))
#endif

#ifndef HTTP_DEBUG
#define HTTP_DEBUG_PRINT(string)
#endif

RestClient::RestClient(const char* _host){
host = _host;
port = 80;
num_headers = 0;
contentTypeSet = false;
}

RestClient::RestClient(const char* _host, int _port){
host = _host;
port = _port;
num_headers = 0;
contentTypeSet = false;
}

RestClient::RestClient(const char* _host, int _port, const char* _contentType){
host = _host;
port = _port;
num_headers = 0;
contentTypeSet = true;
contentType = _contentType;
}

void RestClient::dhcp(){
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
if (begin(mac) == 0) {
Serial.println("Failed to configure Ethernet using DHCP");
}
//give it time to initialize
delay(1000);
}

int RestClient::begin(byte mac[]){
return Ethernet.begin(mac);
//give it time to initialize
delay(1000);
}

// GET path
int RestClient::get(const char* path){
return request("GET", path, NULL, NULL);
}

//GET path with response
int RestClient::get(const char* path, String* response){
return request("GET", path, NULL, response);
}

// POST path and body
int RestClient::post(const char* path, const char* body){
return request("POST", path, body, NULL);
}

// POST path and body with response
int RestClient::post(const char* path, const char* body, String* response){
return request("POST", path, body, response);
}

// PUT path and body
int RestClient::put(const char* path, const char* body){
return request("PUT", path, body, NULL);
}

// PUT path and body with response
int RestClient::put(const char* path, const char* body, String* response){
return request("PUT", path, body, response);
}

// DELETE path
int RestClient::del(const char* path){
return request("DELETE", path, NULL, NULL);
}

// DELETE path and response
int RestClient::del(const char* path, String* response){
return request("DELETE", path, NULL, response);
}

// DELETE path and body
int RestClient::del(const char* path, const char* body ){
return request("DELETE", path, body, NULL);
}

// DELETE path and body with response
int RestClient::del(const char* path, const char* body, String* response){
return request("DELETE", path, body, response);
}

void RestClient::write(const char* string){
HTTP_DEBUG_PRINT(string);
client.print(string);
}

void RestClient::setHeader(const char* header){
headers[num_headers] = header;
num_headers++;
}

// The mother- generic request method.
//
int RestClient::request(const char* method, const char* path,
const char* body, String* response){

HTTP_DEBUG_PRINT("HTTP: connect\n");

if(client.connect(host, port)){
HTTP_DEBUG_PRINT("HTTP: connected\n");
HTTP_DEBUG_PRINT("REQUEST: \n");
// Make a HTTP request line:
write(method);
write(" ");
write(path);
write(" HTTP/1.1\r\n");
for(int i=0; i<num_headers; i++){
write(headers[i]);
write("\r\n");
}
write("Host: ");
write(host);
write("\r\n");
write("Connection: keep-alive\r\n");

if(body != NULL){
char contentLength[30];
sprintf(contentLength, "Content-Length: %d\r\n", strlen(body));
write(contentLength);

if(!contentTypeSet){
write("Content-Type: application/json\r\n");
}
else{
char contentTypestr[50];
sprintf(contentTypestr, "Content-Type: %s\r\n", contentType);
write(contentTypestr);
}
}

write("\r\n");

if(body != NULL){
write(body);
write("\r\n");
write("\r\n");
}

//make sure you write all those bytes.
delay(100);

HTTP_DEBUG_PRINT("HTTP: call readResponse\n");
int statusCode = readResponse(response);
HTTP_DEBUG_PRINT("HTTP: return readResponse\n");

//cleanup
HTTP_DEBUG_PRINT("HTTP: stop client\n");
num_headers = 0;
client.stop();
delay(50);
HTTP_DEBUG_PRINT("HTTP: client stopped\n");

return statusCode;
}else{
HTTP_DEBUG_PRINT("HTTP Connection failed\n");
return 0;
}
}

int RestClient::readResponse(String* response) {

// an http request ends with a blank line
boolean currentLineIsBlank = true;
boolean httpBody = false;
boolean inStatus = false;

char statusCode[4];
int i = 0;
int code = 0;

if(response == NULL){
HTTP_DEBUG_PRINT("HTTP: NULL RESPONSE POINTER: \n");
}else{
HTTP_DEBUG_PRINT("HTTP: NON-NULL RESPONSE POINTER: \n");
}

HTTP_DEBUG_PRINT("HTTP: RESPONSE: \n");
while (client.connected()) {
HTTP_DEBUG_PRINT(".");
if (client.available()) {
HTTP_DEBUG_PRINT(",");

char c = client.read();
HTTP_DEBUG_PRINT(c);

if(c == ' ' && !inStatus){
inStatus = true;
}

if(inStatus && i < 3 && c != ' '){
statusCode[i] = c;
i++;
}
if(i == 3){
statusCode[i] = '\0';
code = atoi(statusCode);
}

//only write response if its not null
if(httpBody){
if(response != NULL) response->concat(c);
}
if (c == '\n' && httpBody){
HTTP_DEBUG_PRINT("HTTP: return readResponse2\n");
return code;
}
if (c == '\n' && currentLineIsBlank) {
httpBody = true;
}
if (c == '\n') {
// you're starting a new lineu
currentLineIsBlank = true;
}
else if (c != '\r') {
// you've gotten a character on the current line
currentLineIsBlank = false;
}
}
}

HTTP_DEBUG_PRINT("HTTP: return readResponse3\n");
return code;
}
Loading

0 comments on commit 4f1fd6b

Please sign in to comment.