Own fork of MbedSmartRest

Dependents:   MbedSmartRestMain MbedSmartRestMain

Fork of MbedSmartRest by Cumulocity Official

MbedClient.cpp

Committer:
Cumulocity
Date:
2014-07-07
Revision:
2:45a6e44a4fb4
Parent:
1:9a11a331e340
Child:
6:cd7ba1ddb664

File content as of revision 2:45a6e44a4fb4:

/*
 * MbedClient.cpp
 *
 * Created on: Feb 1, 2013
 * * Authors: Vincent Wochnik <v.wochnik@gmail.com>
 *
 * Copyright (c) 2013 Cumulocity GmbH
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include "MbedClient.h"
#include <stdlib.h>
#include <string.h>
#include "b64.h"
#include "mbed.h"

MbedClient::MbedClient(const char* host, uint16_t port) :
    _host(host),
    _port(port),
    _filter(_source),
    _source(_sock),
    _sink(_sock),
    _sock()
{
    _username = NULL;
    _password = NULL;
    _state = MBED_STATE_INIT;
}

MbedClient::~MbedClient()
{
}

uint8_t MbedClient::setAuthorization(const char* username, const char* password)
{
    if (_state != MBED_STATE_INIT)
        return CLIENT_INTERNAL_ERROR;

    _username = username;
    _password = password;
    return CLIENT_OK;
}

uint8_t MbedClient::beginRequest()
{
    if (_state != MBED_STATE_INIT)
        return CLIENT_INTERNAL_ERROR;

    if (_sock.connect(_host, _port) < 0) {
        stop();
        return CLIENT_CONNECTION_ERROR;
    }

    if ((!send("POST /s HTTP/1.0\r\n")) ||
        (!send("Host: ")) ||
        (!send(_host)) ||
        (!send("\r\n")))
        return CLIENT_CONNECTION_ERROR;
    
    if ((_username != NULL) && (strlen(_username) > 0) &&
        (_password != NULL) && (strlen(_password) > 0)) {
        if (!sendBasicAuth())
            return CLIENT_CONNECTION_ERROR;
    }

    _state = MBED_STATE_IN_REQUEST;
    return CLIENT_OK;
}

uint8_t MbedClient::sendIdentifier(const char* identifier)
{
    if (_state != MBED_STATE_IN_REQUEST)
        return CLIENT_INTERNAL_ERROR;

    if ((identifier != NULL) && (strlen(identifier) != 0)) {
        if ((!send("X-Id: ")) ||
            (!send(identifier)) ||
            (!send("\r\n")))
            return CLIENT_CONNECTION_ERROR;
    }

    _state = MBED_STATE_SENT_ID;
    return CLIENT_OK;
}

uint8_t MbedClient::sendData(const DataGenerator& generator)
{
    size_t len; char lenstr[8];
    
    if ((_state != MBED_STATE_IN_REQUEST) && (_state != MBED_STATE_SENT_ID))
        return CLIENT_INTERNAL_ERROR;
    
    len = generator.writtenLength();
    snprintf(lenstr, 8, "%ld", len);
    
    if ((!send("Content-Length: ")) ||
        (!send(lenstr)) ||
        (!send("\r\n\r\n")))
        return CLIENT_CONNECTION_ERROR;

    if (generator.writeTo(_sink) != len) {
        stop();
        return CLIENT_CONNECTION_ERROR;
    }
    
    _state = MBED_STATE_SENT_DATA;
    return CLIENT_OK;
}

uint8_t MbedClient::endRequest()
{
    if ((_state != MBED_STATE_IN_REQUEST) && (_state != MBED_STATE_SENT_ID) && (_state != MBED_STATE_SENT_DATA))
        return CLIENT_INTERNAL_ERROR;
    
    if (_state != MBED_STATE_SENT_DATA) {
        // send end of headers
        if (!send("\r\n"))
            return CLIENT_CONNECTION_ERROR;
    }
    
    if (!_sink.flush()) {
        stop();
        return CLIENT_CONNECTION_ERROR;
    }
    
    _state = MBED_STATE_REQ_COMPLETE;
    return CLIENT_OK;
}

uint8_t MbedClient::awaitResponse()
{
    if (_state != MBED_STATE_REQ_COMPLETE)
        return CLIENT_INTERNAL_ERROR;
    
    if ((_filter.readStatus() != 200) || (!_filter.skipHeaders())) {
        stop();
        return CLIENT_CONNECTION_ERROR;
    }
    
    _state = MBED_STATE_RECVD_RESPONSE;
    return CLIENT_OK;
}

AbstractDataSource& MbedClient::receiveData()
{
    return _filter;
}

void MbedClient::stop()
{
    _sock.close();
    _source.reset();
    _sink.reset();
    _filter.reset();
    _state = MBED_STATE_INIT;
}

bool MbedClient::send(const char *str)
{
    if (_sink.write(str) != strlen(str)) {
        stop();
        return false;
    }
    return true;
}

bool MbedClient::sendBasicAuth()
{
    size_t ul, pl; unsigned char input[3]; unsigned char output[5];
    int inputOffset = 0;

    if (!send("Authorization: Basic "))
        return false;
        
    ul = strlen(_username);
    pl = strlen(_password);

    for (int i = 0; i < (ul+1+pl); i++) {
        if (i < ul)
            input[inputOffset++] = _username[i];
        else if (i == ul)
            input[inputOffset++] = ':';
        else
            input[inputOffset++] = _password[i-(ul+1)];

        if ((inputOffset == 3) || (i == ul+pl)) {
            b64_encode(input, inputOffset, output, 4);
            output[4] = '\0';
            if (!send((char*)output))
                return false;
            inputOffset = 0;
        }
    }
    
    if (!send("\r\n"))
        return false;
    return true;
}