void well_known_core_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) { size_t strpos = 0; /* position in overall string (which is larger than the buffer) */ size_t bufpos = 0; /* position within buffer (bytes written) */ size_t tmplen = 0; resource_t* resource = NULL; #if COAP_LINK_FORMAT_FILTERING /* For filtering. */ const char *filter = NULL; const char *attrib = NULL; const char *found = NULL; const char *end = NULL; char *value = NULL; char lastchar = '\0'; int len = coap_get_header_uri_query(request, &filter); if (len) { value = strchr(filter, '='); value[0] = '\0'; ++value; len -= strlen(filter)+1; PRINTF("Filter %s = %.*s\n", filter, len, value); if (strcmp(filter,"href")==0 && value[0]=='/') { ++value; --len; } lastchar = value[len-1]; value[len-1] = '\0'; } #endif for (resource = (resource_t*)list_head(rest_get_resources()); resource; resource = resource->next) { #if COAP_LINK_FORMAT_FILTERING /* Filtering */ if (len) { if (strcmp(filter,"href")==0) { attrib=strstr(resource->url, value); if (attrib==NULL || (value[-1]=='/' && attrib!=resource->url)) continue; end = attrib + strlen(attrib); } else { attrib=strstr(resource->attributes, filter); if (attrib==NULL || (attrib[strlen(filter)]!='=' && attrib[strlen(filter)]!='"')) continue; attrib += strlen(filter)+2; end = strchr(attrib, '"'); } PRINTF("Filter: res has attrib %s (%s)\n", attrib, value); found = attrib; while ((found=strstr(found, value))!=NULL) { if (found > end) { found = NULL; break; } if (lastchar==found[len-1] || lastchar=='*') { break; } ++found; } if (found==NULL) { continue; } PRINTF("Filter: res has prefix %s\n", found); if (lastchar!='*' && (found[len]!='"' && found[len]!=' ' && found[len]!='\0')) continue; PRINTF("Filter: res has match\n"); } #endif PRINTF("res: /%s (%p)\npos: s%d, o%ld, b%d\n", resource->url, resource, strpos, *offset, bufpos); if (strpos>0) { if (strpos >= *offset && bufpos < preferred_size) { buffer[bufpos++] = ','; } ++strpos; } if (strpos >= *offset && bufpos < preferred_size) { buffer[bufpos++] = '<'; } ++strpos; if (strpos >= *offset && bufpos < preferred_size) { buffer[bufpos++] = '/'; } ++strpos; tmplen = strlen(resource->url); if (strpos+tmplen > *offset) { bufpos += snprintf((char *) buffer + bufpos, preferred_size - bufpos + 1, "%s", resource->url + ((*offset-(int32_t)strpos > 0) ? (*offset-(int32_t)strpos) : 0)); /* minimal-net requires these casts */ if (bufpos >= preferred_size) { break; } } strpos += tmplen; if (strpos >= *offset && bufpos < preferred_size) { buffer[bufpos++] = '>'; } ++strpos; if (resource->attributes[0]) { if (strpos >= *offset && bufpos < preferred_size) { buffer[bufpos++] = ';'; } ++strpos; tmplen = strlen(resource->attributes); if (strpos+tmplen > *offset) { bufpos += snprintf((char *) buffer + bufpos, preferred_size - bufpos + 1, "%s", resource->attributes + (*offset-(int32_t)strpos > 0 ? *offset-(int32_t)strpos : 0)); if (bufpos >= preferred_size) { break; } } strpos += tmplen; } /* buffer full, but resource not completed yet; or: do not break if resource exactly fills buffer. */ if (bufpos >= preferred_size && strpos-bufpos > *offset) { PRINTF("res: BREAK at %s (%p)\n", resource->url, resource); break; } } if (bufpos>0) { PRINTF("BUF %d: %.*s\n", bufpos, bufpos, (char *) buffer); coap_set_payload(response, buffer, bufpos ); coap_set_header_content_type(response, APPLICATION_LINK_FORMAT); } else if (strpos>0) { PRINTF("well_known_core_handler(): bufpos<=0\n"); coap_set_status_code(response, BAD_OPTION_4_02); coap_set_payload(response, "BlockOutOfScope", 15); } if (resource==NULL) { PRINTF("res: DONE\n"); *offset = -1; } else { PRINTF("res: MORE at %s (%p)\n", resource->url, resource); *offset += preferred_size; } }
/*---------------------------------------------------------------------------*/ void well_known_core_get_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) { size_t strpos = 0; /* position in overall string (which is larger than the buffer) */ size_t bufpos = 0; /* position within buffer (bytes written) */ resource_t *resource = NULL; #if COAP_LINK_FORMAT_FILTERING /* For filtering. */ const char *filter = NULL; const char *attrib = NULL; const char *found = NULL; const char *end = NULL; char *value = NULL; char lastchar = '\0'; int len = coap_get_header_uri_query(request, &filter); if(len) { value = strchr(filter, '='); value[0] = '\0'; ++value; len -= strlen(filter) + 1; PRINTF("Filter %s = %.*s\n", filter, len, value); if(strcmp(filter, "href") == 0 && value[0] == '/') { ++value; --len; } lastchar = value[len - 1]; value[len - 1] = '\0'; } #endif for(resource = (resource_t *)list_head(rest_get_resources()); resource; resource = resource->next) { size_t tmplen = 0; #if COAP_LINK_FORMAT_FILTERING /* Filtering */ if(len) { if(strcmp(filter, "href") == 0) { attrib = strstr(resource->url, value); if(attrib == NULL || (value[-1] == '/' && attrib != resource->url)) { continue; } end = attrib + strlen(attrib); } else if(resource->attributes != NULL) { attrib = strstr(resource->attributes, filter); if(attrib == NULL || (attrib[strlen(filter)] != '=' && attrib[strlen(filter)] != '"')) { continue; } attrib += strlen(filter) + 2; end = strchr(attrib, '"'); } PRINTF("Filter: res has attrib %s (%s)\n", attrib, value); found = attrib; while((found = strstr(found, value)) != NULL) { if(found > end) { found = NULL; break; } if(lastchar == found[len - 1] || lastchar == '*') { break; } ++found; } if(found == NULL) { continue; } PRINTF("Filter: res has prefix %s\n", found); if(lastchar != '*' && (found[len] != '"' && found[len] != ' ' && found[len] != '\0')) { continue; } PRINTF("Filter: res has match\n"); } #endif PRINTF("res: /%s (%p)\npos: s%zu, o%ld, b%zu\n", resource->url, resource, strpos, (long)*offset, bufpos); if(strpos > 0) { ADD_CHAR_IF_POSSIBLE(','); } ADD_CHAR_IF_POSSIBLE('<'); ADD_CHAR_IF_POSSIBLE('/'); ADD_STRING_IF_POSSIBLE(resource->url, >=); ADD_CHAR_IF_POSSIBLE('>'); if(resource->attributes != NULL && resource->attributes[0]) { ADD_CHAR_IF_POSSIBLE(';'); ADD_STRING_IF_POSSIBLE(resource->attributes, >); } /* buffer full, but resource not completed yet; or: do not break if resource exactly fills buffer. */ if(bufpos > preferred_size && strpos - bufpos > *offset) { PRINTF("res: BREAK at %s (%p)\n", resource->url, resource); break; } }
static int coap_HandleRequest(void *packet, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) { int result = 1; const char *url = NULL; int urlLen = 0; const uint8_t * payload = NULL; int payloadLen = 0; int content = -1; coap_packet_t * const request = (coap_packet_t *) packet; CoapResponse coapResponse = { .responseContent = buffer, .responseContentLen = preferred_size, .responseCode = 400, }; payloadLen = coap_get_payload(request, &payload); if ((urlLen = coap_get_header_uri_path(request, &url))) { char uriBuf[MAX_COAP_PATH] = { 0 }; rest_resource_flags_t method = (rest_resource_flags_t) (1 << (((coap_packet_t *) packet)->code - 1)); //coap_get_rest_method(request); uriBuf[0] = '/'; memcpy(&uriBuf[1], url, urlLen); char queryBuf[128] = "?"; const char * query = NULL; int queryLength = coap_get_header_uri_query(request, &query); if (queryLength > 0) memcpy(&queryBuf[1], query, queryLength); queryBuf[queryLength+1] = '\0'; CoapRequest coapRequest = { .ctxt = context, .addr = { 0 }, .path = uriBuf, .query = queryBuf, .token = request->token, .tokenLength = request->token_len, .requestContent = payload, .requestContentLen = payloadLen, }; NetworkAddress_SetAddressType(sourceAddress, &coapRequest.addr); switch (method) { case METHOD_GET: coap_get_header_accept(request, &content); coapRequest.contentType = content; int32_t observe; if (!coap_get_header_observe(request, &observe)) observe = -1; switch (observe) { case -1: Lwm2m_Debug("Coap GET for %s\n", uriBuf); coapRequest.type = COAP_GET_REQUEST; requestHandler(&coapRequest, &coapResponse); break; case 0: Lwm2m_Debug("Coap OBSERVE for %s\n", uriBuf); coapRequest.type = COAP_OBSERVE_REQUEST; requestHandler(&coapRequest, &coapResponse); coap_set_header_observe(response, 1); break; case 1: Lwm2m_Debug("Coap CANCEL OBSERVE for %s\n", uriBuf); coapRequest.type = COAP_CANCEL_OBSERVE_REQUEST; requestHandler(&coapRequest, &coapResponse); break; default: break; } coap_set_header_content_format(response, coapResponse.responseContentType); /* text/plain is the default, hence this option could be omitted. */ break; case METHOD_POST: coap_get_header_content_format(request, &content); coapRequest.contentType = content; coapRequest.type = COAP_POST_REQUEST; Lwm2m_Debug("Coap POST for %s\n", uriBuf); requestHandler(&coapRequest, &coapResponse); if (coapResponse.responseContentLen > 0 && coapResponse.responseCode == 201) { coap_set_header_location_path(response, coapResponse.responseContent); } break; case METHOD_PUT: coap_get_header_content_format(request, &content); coapRequest.contentType = content; coapRequest.type = COAP_PUT_REQUEST; Lwm2m_Debug("Coap PUT for %s\n", uriBuf); requestHandler(&coapRequest, &coapResponse); break; case METHOD_DELETE: coapRequest.contentType = ContentType_None; coapRequest.type = COAP_DELETE_REQUEST; Lwm2m_Debug("Coap DELETE for %s\n", uriBuf); requestHandler(&coapRequest, &coapResponse); break; default: break; } if (coapResponse.responseContentLen > 0 && coapResponse.responseCode == 205) { coap_set_payload(response, coapResponse.responseContent, coapResponse.responseContentLen); } } coap_set_status_code(response, COAP_RESPONSE_CODE(coapResponse.responseCode)); return result; }