Ejemplo n.º 1
0
/**
 * @brief Upgrade a client's connection to SSL/TLS
 *
 * This function begins the SSL handshake process on connected client @p client.
 * An AZY_CLIENT_UPGRADE event will be emitted on success, and EINA_FALSE will be
 * returned immediately on failure.
 * @param client The client object (NOT NULL)
 * @return #EINA_TRUE if successful, or #EINA_FALSE on failure
 */
Eina_Bool
azy_client_upgrade(Azy_Client *client)
{
   DBG("(client=%p)", client);

   if (!AZY_MAGIC_CHECK(client, AZY_MAGIC_CLIENT))
     {
        AZY_MAGIC_FAIL(client, AZY_MAGIC_CLIENT);
        return EINA_FALSE;
     }
   if (!client->connected) return EINA_FALSE;

   return ecore_con_ssl_server_upgrade(client->net->conn, ECORE_CON_USE_MIXED);
}
Ejemplo n.º 2
0
/**
 * @brief Returns the currently active call id
 *
 * This function returns the currently active #Azy_Client_Call_Id, or 0 if no call
 * is currently active/pending.
 * @param cli The client object (NOT NULL)
 * @return The currently active/pending call id, or 0 on failure
 */
Azy_Client_Call_Id
azy_client_current(Azy_Client *cli)
{
   Azy_Client_Handler_Data *hd;

   if (!AZY_MAGIC_CHECK(cli, AZY_MAGIC_CLIENT))
     {
        AZY_MAGIC_FAIL(cli, AZY_MAGIC_CLIENT);
        return 0;
     }

   if (!cli->conns) return 0;

   hd = cli->conns->data;
   return hd->id;
}
Ejemplo n.º 3
0
/**
 * @brief Set the port that the client connects to
 *
 * This function sets the port number on the server that @p client
 * connects to.
 * @param client The client object (NOT NULL)
 * @param port The port number (-1 < port < 65536)
 * @return #EINA_TRUE on success, or #EINA_FALSE on failure
 */
Eina_Bool
azy_client_port_set(Azy_Client *client,
                    int         port)
{
   DBG("(client=%p)", client);
   if (!AZY_MAGIC_CHECK(client, AZY_MAGIC_CLIENT))
     {
        AZY_MAGIC_FAIL(client, AZY_MAGIC_CLIENT);
        return EINA_FALSE;
     }
   if ((port < 0) || (port > 65535))
     return EINA_FALSE;

   client->port = port;
   return EINA_TRUE;
}
Ejemplo n.º 4
0
/**
 * @brief Upgrade a client's connection to SSL/TLS
 *
 * This function begins the SSL handshake process on connected client represented by @p module.
 * An AZY_EVENT_SERVER_CLIENT_UPGRADE event will be emitted on success, and EINA_FALSE will be
 * returned immediately on failure.
 * @param module The client object (NOT NULL)
 * @return #EINA_TRUE if successful, or #EINA_FALSE on failure
 */
Eina_Bool
azy_server_module_upgrade(Azy_Server_Module *module)
{
   DBG("(module=%p)", module);

   if (!AZY_MAGIC_CHECK(module, AZY_MAGIC_SERVER_MODULE))
     {
        AZY_MAGIC_FAIL(module, AZY_MAGIC_SERVER_MODULE);
        return EINA_FALSE;
     }
   if (module->client->dead) return EINA_FALSE;

   if (!ecore_con_ssl_client_upgrade(module->client->net->conn, ECORE_CON_USE_MIXED)) return EINA_FALSE;
   module->client->upgrading_module = module;
   return EINA_TRUE;
}
Ejemplo n.º 5
0
/**
 * @brief Free the given #Azy_Server_Module_Def
 *
 * This function frees the given #Azy_Server_Module_Def, and should only
 * be called after the module will no longer be used.
 * @param def The #Azy_Server_Module_Def to free
 */
void
azy_server_module_def_free(Azy_Server_Module_Def *def)
{
   if (!def) return;
   if (!AZY_MAGIC_CHECK(def, AZY_MAGIC_SERVER_MODULE_DEF))
     {
        AZY_MAGIC_FAIL(def, AZY_MAGIC_SERVER_MODULE_DEF);
        return;
     }

   eina_stringshare_del(def->name);
   eina_hash_free(def->methods);
   if (def->module) eina_module_free(def->module);

   AZY_MAGIC_SET(def, AZY_MAGIC_NONE);
   free(def);
}
Ejemplo n.º 6
0
/**
 * @brief Get a param from a module
 *
 * This function gets a previously set method call param
 * named @p name from module @p module. It is used by the parser.
 * @param module The module (NOT NULL)
 * @param name The param name (NOT NULL)
 * @return The param value, NULL on failure
 */
void *
azy_server_module_param_get(Azy_Server_Module *module, const char *name)
{
   Azy_Server_Module_Param *param;
   if (!AZY_MAGIC_CHECK(module, AZY_MAGIC_SERVER_MODULE))
     {
        AZY_MAGIC_FAIL(module, AZY_MAGIC_SERVER_MODULE);
        return NULL;
     }
   EINA_SAFETY_ON_NULL_RETURN_VAL(name, NULL);
   EINA_SAFETY_ON_NULL_RETURN_VAL(module->params, NULL);
   EINA_SAFETY_ON_TRUE_RETURN_VAL(!name[0], NULL);

   param = eina_hash_find(module->params, name);
   EINA_SAFETY_ON_NULL_RETURN_VAL(param, NULL);
   return (void *)param->data;
}
Ejemplo n.º 7
0
/**
 * @brief Set the address of the server that the client connects to
 *
 * This function sets the address string of the server that @p client
 * connects to.
 * @param client The client object (NOT NULL)
 * @param addr The address string (NOT NULL)
 * @return The address string
 */
Eina_Bool
azy_client_addr_set(Azy_Client *client,
                    const char *addr)
{
   DBG("(client=%p)", client);
   if (!AZY_MAGIC_CHECK(client, AZY_MAGIC_CLIENT))
     {
        AZY_MAGIC_FAIL(client, AZY_MAGIC_CLIENT);
        return EINA_FALSE;
     }
   EINA_SAFETY_ON_NULL_RETURN_VAL(addr, EINA_FALSE);
   if (!strncmp(addr, "http://", 7))
     addr += 7;
   else if (!strncmp(addr, "https://", 8))
     addr += 8;
   client->addr = eina_stringshare_add(addr);
   return EINA_TRUE;
}
Ejemplo n.º 8
0
/**
 * @brief Close a client's connection
 *
 * This function is the opposite of azy_client_connect, it
 * terminates an existing connection.
 * @param client The client (NOT NULL)
 */
void
azy_client_close(Azy_Client *client)
{
   DBG("(client=%p)", client);

   if (!AZY_MAGIC_CHECK(client, AZY_MAGIC_CLIENT))
     {
        AZY_MAGIC_FAIL(client, AZY_MAGIC_CLIENT);
        return;
     }
   EINA_SAFETY_ON_FALSE_RETURN(client->connected);
   EINA_SAFETY_ON_NULL_RETURN(client->net);

   ecore_con_server_del(client->net->conn);

   azy_net_free(client->net);
   client->net = NULL;

   client->connected = EINA_FALSE;
}
Ejemplo n.º 9
0
/**
 * @brief Set a callback to free the return struct of @p id
 *
 * This function, when set, frees the returned user-type struct of a call.
 * @param client The client
 * @param id The transmission id
 * @param callback The free callback
 */
Eina_Bool
azy_client_callback_free_set(Azy_Client        *client,
                             Azy_Client_Call_Id id,
                             Ecore_Cb           callback)
{
   DBG("(client=%p, id=%u)", client, id);

   if (!AZY_MAGIC_CHECK(client, AZY_MAGIC_CLIENT))
     {
        AZY_MAGIC_FAIL(client, AZY_MAGIC_CLIENT);
        return EINA_FALSE;
     }
   EINA_SAFETY_ON_NULL_RETURN_VAL(callback, EINA_FALSE);
   EINA_SAFETY_ON_TRUE_RETURN_VAL(id < 1, EINA_FALSE);

   if (!client->free_callbacks)
     client->free_callbacks = eina_hash_int32_new(NULL);
   EINA_SAFETY_ON_NULL_RETURN_VAL(client->free_callbacks, EINA_FALSE);

   return eina_hash_add(client->free_callbacks, &id, callback);
}
Ejemplo n.º 10
0
/**
 * @brief Set a param to a module
 *
 * This function sets a method call param named @p name to a module. It is used by the parser.
 * @param module The module (NOT NULL)
 * @param name The param name (NOT NULL)
 * @param value The param value
 * @param free_func The function to free @p value
 * @return EINA_TRUE on success, else EINA_FALSE
 */
Eina_Bool
azy_server_module_param_set(Azy_Server_Module *module, const char *name, const void *value, Eina_Free_Cb free_func)
{
   Azy_Server_Module_Param *param, *old;
   if (!AZY_MAGIC_CHECK(module, AZY_MAGIC_SERVER_MODULE))
     {
        AZY_MAGIC_FAIL(module, AZY_MAGIC_SERVER_MODULE);
        return EINA_FALSE;
     }
   EINA_SAFETY_ON_NULL_RETURN_VAL(name, EINA_FALSE);
   EINA_SAFETY_ON_TRUE_RETURN_VAL(!name[0], EINA_FALSE);
   if (!module->params) module->params = eina_hash_string_djb2_new((Eina_Free_Cb)azy_server_module_param_free_);
   param = calloc(1, sizeof(Azy_Server_Module_Param));
   EINA_SAFETY_ON_NULL_RETURN_VAL(param, EINA_FALSE);
   param->data = value;
   param->free_func = free_func;

   old = eina_hash_set(module->params, name, param);
   if (old) azy_server_module_param_free_(old);
   return EINA_TRUE;
}
Ejemplo n.º 11
0
/**
 * @brief Helper function to automatically handle redirection
 *
 * This function is used inside an AZY_CLIENT_DISCONNECTED callback to automatically
 * reconnect to the server if necessary (HTTP 301/302/303 returned).
 * @param cli The client object (NOT NULL)
 * @return #EINA_TRUE only if reconnection has succeeded, else #EINA_FALSE
 */
Eina_Bool
azy_client_redirect(Azy_Client *cli)
{
   int code;
   Azy_Net *net;

   if (!AZY_MAGIC_CHECK(cli, AZY_MAGIC_CLIENT))
     {
        AZY_MAGIC_FAIL(cli, AZY_MAGIC_CLIENT);
        return EINA_FALSE;
     }

   net = azy_client_net_get(cli);
   if (!net) return EINA_FALSE;
   code = azy_net_code_get(net);

   if ((code >= 301) && (code <= 303))
     {
        azy_client_connect(cli, cli->secure);
        return EINA_TRUE;
     }
   return EINA_FALSE;
}
Ejemplo n.º 12
0
/**
 * @brief Add a module to the server object
 *
 * This function adds @p module to @p server.  After calling this,
 * the module should not be freed until the server has stopped running.
 * @param server The server object (NOT NULL)
 * @param module The module definition (NOT NULL)
 * @return EINA_TRUE on success, else EINA_FALSE
 */
Eina_Bool
azy_server_module_add(Azy_Server *server,
                      Azy_Server_Module_Def *module)
{
   if (!AZY_MAGIC_CHECK(server, AZY_MAGIC_SERVER))
     {
        AZY_MAGIC_FAIL(server, AZY_MAGIC_SERVER);
        return EINA_FALSE;
     }
   if (!module) return EINA_FALSE;
   if (server->module_defs)
     {
        if (azy_server_module_def_find(server, module->name))
          /* avoid adding same module twice */
          return EINA_TRUE;
     }
   else
     server->module_defs = eina_hash_string_superfast_new(NULL);
   if (!server->module_defs) return EINA_FALSE;

   INFO("Adding new module: '%s'", module->name);
   return eina_hash_add(server->module_defs, module->name, module);
}
Ejemplo n.º 13
0
/**
 * @brief Make an HTTP GET or POST request using a connected client with no HTTP BODY
 *
 * This function is used to make a GET or POST request using @p client to the uri of the client's
 * #Azy_Net object (azy_net_get(client)) using HTTP method @p type, content-type
 * defined by @p transport, and the optional deserialization function specified by @p cb.
 * @param client The client (NOT NULL)
 * @param type The HTTP method to use (NOT NULL)
 * @param netdata The HTTP BODY to send with a POST
 * @param cb The deserialization callback to use for the response
 * @param data The user data to be passed to resulting callbacks
 * @return The #Azy_Client_Call_Id of the transmission, to be used with azy_client_callback_set,
 * or 0 on failure
 */
Azy_Client_Call_Id
azy_client_blank(Azy_Client    *client,
                 Azy_Net_Type   type,
                 Azy_Net_Data  *netdata,
                 Azy_Content_Cb cb,
                 void          *data)
{
   Eina_Strbuf *msg;
   Azy_Client_Handler_Data *hd;

   DBG("(client=%p, net=%p)", client, client->net);

   if (!AZY_MAGIC_CHECK(client, AZY_MAGIC_CLIENT))
     {
        AZY_MAGIC_FAIL(client, AZY_MAGIC_CLIENT);
        return 0;
     }
   EINA_SAFETY_ON_NULL_RETURN_VAL(client->net, 0);
   EINA_SAFETY_ON_TRUE_RETURN_VAL((type != AZY_NET_TYPE_GET) && (type != AZY_NET_TYPE_POST), 0);

   while (++azy_client_send_id__ < 1) ;

   client->net->type = type;

   if (!client->net->http.req.http_path)
     {
        WARN("NULL URI passed, defaulting to \"/\"");
        azy_net_uri_set(client->net, "/");
     }
   if (netdata && netdata->size && (type == AZY_NET_TYPE_POST))
     azy_net_message_length_set(client->net, netdata->size);

   msg = azy_net_header_create(client->net);
   EINA_SAFETY_ON_NULL_GOTO(msg, error);

#ifdef ISCOMFITOR
   char buf[64];
   snprintf(buf, sizeof(buf), "\nSENDING >>>>>>>>>>>>>>>>>>>>>>>>\n%%.%zus\n>>>>>>>>>>>>>>>>>>>>>>>>",
            eina_strbuf_length_get(msg));
   DBG(buf, eina_strbuf_string_get(msg));
#endif

   EINA_SAFETY_ON_TRUE_GOTO(!ecore_con_server_send(client->net->conn, eina_strbuf_string_get(msg), eina_strbuf_length_get(msg)), error);
   if (netdata && netdata->size && (type == AZY_NET_TYPE_POST))
     {
        INFO("Send [1/2] complete! %zu bytes queued for sending.", eina_strbuf_length_get(msg));
        EINA_SAFETY_ON_TRUE_GOTO(!ecore_con_server_send(client->net->conn, netdata->data, netdata->size), error);
        INFO("Send [2/2] complete! %" PRIi64 " bytes queued for sending.", netdata->size);
     }
   else
     INFO("Send [1/1] complete! %zu bytes queued for sending.", eina_strbuf_length_get(msg));
   eina_strbuf_free(msg);
   msg = NULL;

   ecore_con_server_flush(client->net->conn);

   hd = calloc(1, sizeof(Azy_Client_Handler_Data));
   EINA_SAFETY_ON_NULL_RETURN_VAL(hd, 0);
   hd->client = client;
   hd->callback = cb;
   hd->type = type;
   hd->content_data = data;
   if (netdata && netdata->size && (type == AZY_NET_TYPE_POST))
     {
        hd->send = eina_strbuf_new();
        eina_strbuf_append_length(hd->send, (char *)netdata->data, netdata->size);
     }

   hd->id = azy_client_send_id__;
   AZY_MAGIC_SET(hd, AZY_MAGIC_CLIENT_DATA_HANDLER);
   if (!client->conns)
     {
        client->recv = ecore_event_handler_add(ECORE_CON_EVENT_SERVER_DATA,
                                               (Ecore_Event_Handler_Cb)_azy_client_handler_data, hd);
        ecore_con_server_data_set(client->net->conn, client);
     }

   client->conns = eina_list_append(client->conns, hd);

   DBG("(client=%p, net=%p, hd=%p)", client, client->net, hd);
   return azy_client_send_id__;
error:
   if (msg) eina_strbuf_free(msg);
   return 0;
}
Ejemplo n.º 14
0
/**
 * @brief Make a method call using a connected client
 *
 * This function is used to make a method call on @p client as defined in
 * @p content, using content-type defined by @p transport and the deserialization
 * function specified by @p cb.  This should generally not be used by users, as azy_parser
 * will automatically generate the correct calls from a .azy file.
 * @param client The client (NOT NULL)
 * @param content The content containing the method name and parameters (NOT NULL)
 * @param transport The content-type (xml/json/etc) to use
 * @param cb The deserialization callback to use for the response
 * @return The #Azy_Client_Call_Id of the transmission, to be used with azy_client_callback_set,
 * or 0 on failure
 */
Azy_Client_Call_Id
azy_client_call(Azy_Client       *client,
                Azy_Content      *content,
                Azy_Net_Transport transport,
                Azy_Content_Cb    cb)
{
   Eina_Strbuf *msg;
   Azy_Client_Handler_Data *hd;

   DBG("(client=%p, net=%p, content=%p)", client, client->net, content);

   if (!AZY_MAGIC_CHECK(client, AZY_MAGIC_CLIENT))
     {
        AZY_MAGIC_FAIL(client, AZY_MAGIC_CLIENT);
        return 0;
     }
   EINA_SAFETY_ON_NULL_RETURN_VAL(client->net, 0);
   EINA_SAFETY_ON_NULL_RETURN_VAL(content, 0);
   EINA_SAFETY_ON_NULL_RETURN_VAL(content->method, 0);

   INFO("New method call: '%s'", content->method);

   while (++azy_client_send_id__ < 1) ;

   content->id = azy_client_send_id__;

   azy_net_transport_set(client->net, transport);
   if (!azy_content_serialize_request(content, transport))
     return 0;
   azy_net_type_set(client->net, AZY_NET_TYPE_POST);
   if (!client->net->http.req.http_path)
     {
        WARN("URI currently set to NULL, defaulting to \"/\"");
        azy_net_uri_set(client->net, "/");
     }

   azy_net_message_length_set(client->net, content->length);
   msg = azy_net_header_create(client->net);
   EINA_SAFETY_ON_NULL_GOTO(msg, error);

   if (azy_rpc_log_dom >= 0)
     {
        char buf[64];
        snprintf(buf, sizeof(buf), "\nSENDING >>>>>>>>>>>>>>>>>>>>>>>>\n%%.%is%%.%llis\n>>>>>>>>>>>>>>>>>>>>>>>>",
            eina_strbuf_length_get(msg), content->length);
        RPC_DBG(buf, eina_strbuf_string_get(msg), content->buffer);
     }

   EINA_SAFETY_ON_TRUE_GOTO(!ecore_con_server_send(client->net->conn, eina_strbuf_string_get(msg), eina_strbuf_length_get(msg)), error);
   INFO("Send [1/2] complete! %zu bytes queued for sending.", eina_strbuf_length_get(msg));
   eina_strbuf_free(msg);
   msg = NULL;

   EINA_SAFETY_ON_TRUE_GOTO(!ecore_con_server_send(client->net->conn, content->buffer, content->length), error);
   INFO("Send [2/2] complete! %lli bytes queued for sending.", content->length);
   ecore_con_server_flush(client->net->conn);

   hd = calloc(1, sizeof(Azy_Client_Handler_Data));
   EINA_SAFETY_ON_NULL_RETURN_VAL(hd, 0);
   hd->client = client;
   hd->method = eina_stringshare_ref(content->method);
   hd->callback = cb;
   hd->type = AZY_NET_TYPE_POST;
   hd->content_data = content->data;
   hd->send = eina_strbuf_new();
   eina_strbuf_append_length(hd->send, (char *)content->buffer, content->length);

   hd->id = azy_client_send_id__;
   AZY_MAGIC_SET(hd, AZY_MAGIC_CLIENT_DATA_HANDLER);
   if (!client->conns)
     {
        client->recv = ecore_event_handler_add(ECORE_CON_EVENT_SERVER_DATA,
                                               (Ecore_Event_Handler_Cb)_azy_client_handler_data, hd);
        ecore_con_server_data_set(client->net->conn, client);
     }

   client->conns = eina_list_append(client->conns, hd);

   DBG("(client=%p, net=%p, content=%p, hd=%p)", client, client->net, content, hd);
   return azy_client_send_id__;
error:
   if (msg)
     eina_strbuf_free(msg);
   return 0;
}
Ejemplo n.º 15
0
Eina_Bool
azy_events_header_parse(Azy_Net       *net,
                        unsigned char *event_data,
                        size_t         event_len,
                        int            offset)
{
   unsigned char *r = NULL, *p = NULL, *start = NULL, *buf_start = NULL;
   unsigned char *data = (event_data) ? event_data + offset : NULL;
   int64_t len = (event_len) ? event_len - offset : 0;
   const char *s = NULL;
   unsigned char slen = 0;
   unsigned char sep[5];
   int line_len = 0;
   int64_t prev_size = 0;

   DBG("(net=%p, event_data=%p, len=%zu, offset=%i)", net, event_data, event_len, offset);
   if (!AZY_MAGIC_CHECK(net, AZY_MAGIC_NET))
     {
        AZY_MAGIC_FAIL(net, AZY_MAGIC_NET);
        return EINA_FALSE;
     }
   if (net->headers_read)
     return EINA_TRUE;
   EINA_SAFETY_ON_TRUE_RETURN_VAL((!net->buffer) && (!data), EINA_FALSE);

   if (net->size && net->buffer)
     {
        if (event_data && (azy_rpc_log_dom >= 0))
          {
             char buf[64];
             snprintf(buf, sizeof(buf), "STORED:\n<<<<<<<<<<<<<\n%%.%llis\n<<<<<<<<<<<<<", net->size);
             RPC_INFO(buf, net->buffer);
             snprintf(buf, sizeof(buf), "RECEIVED:\n<<<<<<<<<<<<<\n%%.%llis\n<<<<<<<<<<<<<", len - offset);
             RPC_INFO(buf, data);
          }
        /* previous buffer */
        /* alloca should be safe here because ecore_con reads at most 64k
         * and even if no headers were found previously, the entire
         * buffer would not be copied
         */
        buf_start = alloca(len + net->size - offset);
        /* grab and combine buffers */
        if (event_data)
          {
             memcpy(buf_start, net->buffer + offset, net->size - offset);
             memcpy(buf_start + net->size, event_data, len);
          }
        else
          memcpy(buf_start, net->buffer + offset, net->size - offset);

        free(net->buffer);
        net->buffer = NULL;
        len += net->size - offset;

        prev_size = net->size;
        net->size = 0;
        start = buf_start;
        AZY_SKIP_BLANK(start);
     }
   else
   /* only current buffer plus possible net->overflow */
     {
        /* copy pointer */
         start = data;
         /* skip all spaces/newlines/etc and decrement len */
         AZY_SKIP_BLANK(start);
     }

   if ((!len) && (event_len - offset > 0)) /* only blanks were passed, assume http separator */
     {
        net->headers_read = EINA_TRUE;
        return EINA_TRUE;
     }
   /* apparently this can happen? */
   EINA_SAFETY_ON_NULL_RETURN_VAL(start, EINA_FALSE);
   /* find a header or append to buffer */
   if ((!(r = memchr(start, '\r', len)) && !(r = memchr(start, '\n', len)))) /* append to a buffer and use net->overflow */
     {
        unsigned char *tmp;

        if (net->size)
          {
             tmp = realloc(net->buffer, net->size + len);
             EINA_SAFETY_ON_NULL_RETURN_VAL(tmp, EINA_FALSE);

             net->buffer = tmp;
             memcpy(net->buffer + net->size, start, len);
             net->size += len;
          }
        else
          {
             tmp = realloc(net->buffer, len);
             EINA_SAFETY_ON_NULL_RETURN_VAL(tmp, EINA_FALSE);

             net->buffer = tmp;
             memcpy(net->buffer, start, len);
             net->size = len;
          }
        return EINA_TRUE;
     }

   if (*r == '\r')
     {
        unsigned char *x;
        if ((x = memchr(start, '\n', len)))
          {
             if ((x - r) > 0)
               s = "\r\n";
             else
               { /* we currently have \n\r: b64 encoding can leave a trailing \n
                  * so we have to check for an extra \n
                  */
                   if ((x - r < 0) && ((unsigned int)(r + 1 - start) < len) && (r[1] == '\n')) /* \n\r\n */
                     {
                        if (((unsigned int)(r + 2 - start) < len) && (r[2] == '\r')) /* \n\r\n\r */
                          {
                             if (((unsigned int)(r + 3 - start) < len) && (r[3] == '\n'))
                               /* \n\r\n\r\n oh hey I'm gonna stop here before it gets too insane */
                               s = "\r\n";
                             else
                               s = "\n\r";
                          }
                        else
                          s = "\r\n";
                     }
                   else
                     s = "\n\r";
               }
          }
        else
          s = "\r";
     }
   else
     s = "\n";

   slen = strlen(s);
   snprintf((char *)sep, sizeof(sep), "%s%s", s, s);

   p = start;
   line_len = r - p;
   while (len && r)
     {
        unsigned char *ptr, *semi = p;

        if (line_len > MAX_HEADER_SIZE)
          {
             WARN("Ignoring unreasonably large header starting with:\n %.32s\n", p);
             goto skip_header;
          }
        semi += (line_len - _azy_events_valid_header_name((const char *)p, line_len));
        if (semi == p) goto skip_header;

        ptr = semi + 1;
        while ((isspace(*ptr)) && (ptr - p < line_len))
          ptr++;

        if (_azy_events_valid_header_value((const char *)ptr, line_len - (ptr - p)))
          {
             const char *key, *value;

             p[semi - p] = 0;
             ptr[line_len - (ptr - p)] = 0;
             key = (const char *)p;
             value = (const char *)ptr;
             INFO("Found header: key='%s'", key);
             INFO("Found header: value='%s'", value);
             azy_net_header_set(net, key, value);
             if (!strcasecmp(key, "content-length"))
               net->http.content_length = strtol((const char *)value, NULL, 10);
          }

skip_header:
        len -= line_len + slen;
        if (len < slen)
          break;
        p = r + slen;
        /* double separator: STOP */
        if (!strncmp((char*)p, s, slen))
          {
             net->headers_read = EINA_TRUE;
             break;
          }
        r = azy_memstr(p, (const unsigned char *)s, len, slen);
        line_len = r - p;
        /* FIXME: to be fully 1.1 compliant, lines without a colon
         * be filtered and checked to see if is a continuing header
         * from the previous line
         */
     }

   AZY_SKIP_BLANK(p);

   if (!net->headers_read)
     return EINA_TRUE;

   if (!net->http.content_length) net->http.content_length = -1;
   if (len)
     {
        int64_t rlen;
        /* if we get here, we need to append to the buffers */

        if (net->http.content_length > 0)
          {
             if (len > net->http.content_length)
               {
                  rlen = net->http.content_length;
                  net->overflow_length = len - rlen;
                  WARN("Extra content length of %lli!", net->overflow_length);
                  net->overflow = malloc(net->overflow_length);
     /* FIXME: uhhhh f**k? */
                  EINA_SAFETY_ON_NULL_RETURN_VAL(net->overflow, EINA_FALSE);
                  memcpy(net->overflow, p + rlen, net->overflow_length);
#ifdef ISCOMFITOR
                if (azy_rpc_log_dom >= 0)
                  {
                     int64_t x;
                     RPC_INFO("OVERFLOW:\n<<<<<<<<<<<<<");
                     for (x = 0; x < net->overflow_length; x++)
                       putc(net->overflow[x], stdout);
                     fflush(stdout);
                  }
#endif
               }
             else
               rlen = len;
          }
        else
          /* this shouldn't be possible unless someone is violating spec */
          rlen = len;

        INFO("Set recv size to %lli (previous %lli)", rlen, prev_size);
        net->size = rlen;
        net->buffer = malloc(rlen);
        /* FIXME: cleanup */
        EINA_SAFETY_ON_NULL_RETURN_VAL(net->buffer, EINA_FALSE);

        memcpy(net->buffer, p, rlen);
     }

   return EINA_TRUE;
}
Ejemplo n.º 16
0
/**
 * @brief Send data to a client
 *
 * This function is used to queue arbitrary data to send to a client through its module.  It will automatically
 * generate all http header strings from @p net (if provided) including the content-length (based on @p data).
 * @param module The client's #Azy_Server_Module object (NOT NULL)
 * @param net An #Azy_Net object containing http information to use
 * @param data The data to send
 * @return EINA_TRUE on success, else EINA_FALSE
 */
Eina_Bool
azy_server_module_send(Azy_Server_Module *module,
                       Azy_Net *net,
                       const Azy_Net_Data *data)
{
   Eina_Strbuf *header;
   char chunk_size[20];
   Eina_Binbuf *chunk_data;
   Eina_Bool nullify = EINA_FALSE;

   if (!AZY_MAGIC_CHECK(module, AZY_MAGIC_SERVER_MODULE))
     {
        AZY_MAGIC_FAIL(module, AZY_MAGIC_SERVER_MODULE);
        return EINA_FALSE;
     }

   if (net)
     {
        if (!module->client->current)
          {
             module->client->current = net;
             nullify = EINA_TRUE;
          }

        if (net->headers_sent)
          goto post_header;

        Eina_Bool s;
        if ((data) && (net->http.transfer_encoding != AZY_NET_TRANSFER_ENCODING_CHUNKED))
          azy_net_content_length_set(net, data->size);
        if (!net->http.res.http_code)
          azy_net_code_set(net, 200);  /* OK */
        azy_net_type_set(net, AZY_NET_TYPE_RESPONSE);
        EINA_SAFETY_ON_TRUE_RETURN_VAL(!(header = azy_net_header_create(net)), EINA_FALSE);
        EINA_SAFETY_ON_NULL_RETURN_VAL(module->client->current->conn, EINA_FALSE);
        s = !!ecore_con_client_send(module->client->current->conn, eina_strbuf_string_get(header), eina_strbuf_length_get(header));
        eina_strbuf_free(header);
        if (!s)
          {
             ERR("Could not queue header for sending!");
             return EINA_FALSE;
          }
        net->headers_sent = EINA_TRUE;
     }

post_header:

   if ((!net) || (net->http.transfer_encoding != AZY_NET_TRANSFER_ENCODING_CHUNKED))
     {
        if (!data || !data->data) return EINA_TRUE;

        EINA_SAFETY_ON_NULL_RETURN_VAL(module->client->current->conn, EINA_FALSE);
        EINA_SAFETY_ON_TRUE_RETURN_VAL(!ecore_con_client_send(module->client->current->conn, data->data, data->size), EINA_FALSE);
        goto post_send;
     }

   if (!data || !data->data)
     {
        EINA_SAFETY_ON_NULL_RETURN_VAL(module->client->current->conn, EINA_FALSE);
        EINA_SAFETY_ON_TRUE_RETURN_VAL(!ecore_con_client_send(module->client->current->conn, "0\r\n\r\n", 5), EINA_FALSE);
        goto post_send;
     }

   net->refcount++;
   sprintf((char *)chunk_size, "%" PRIx64 "\r\n", data->size);
   chunk_data = eina_binbuf_new();
   eina_binbuf_append_length(chunk_data, (unsigned char *)chunk_size, strlen(chunk_size));
   eina_binbuf_append_length(chunk_data, data->data, data->size);
   eina_binbuf_append_length(chunk_data, (unsigned char *)"\r\n", 2);
   EINA_SAFETY_ON_NULL_RETURN_VAL(module->client->current->conn, EINA_FALSE);
   EINA_SAFETY_ON_TRUE_RETURN_VAL(!ecore_con_client_send(module->client->current->conn,
                                  eina_binbuf_string_get(chunk_data), eina_binbuf_length_get(chunk_data)), EINA_FALSE);
   eina_binbuf_free(chunk_data);


post_send:
   if (nullify) module->client->current = NULL;
   return EINA_TRUE;
}