UtlBoolean SipSubscribeServerEventHandler::getNotifyContent(const UtlString& resourceId, const UtlString& eventTypeKey, const UtlString& eventType, SipPublishContentMgr& contentMgr, const char* acceptHeaderValue, SipMessage& notifyRequest, int& version) { UtlBoolean gotBody = FALSE; // Default behavior is to just go get the content from // the content manager and attach it to the notify HttpBody* messageBody = NULL; UtlBoolean isDefaultEventContent; gotBody = contentMgr.getContent(resourceId, eventTypeKey, eventType, acceptHeaderValue, messageBody, version, isDefaultEventContent); // The body will be freed with the NOTIFY message. if(messageBody) { const char* contentTypePtr = messageBody->getContentType(); UtlString contentType; if(contentTypePtr) { contentType = contentTypePtr; } else { OsSysLog::add(FAC_SIP, PRI_ERR, "SipSubscribeServerEventHandler::getNotifyContent body published for resourceId: '%s' eventTypeKey: '%s' with no content type", resourceId.data() ? resourceId.data() : "<null>", eventTypeKey.data() ? eventTypeKey.data() : "<null>"); contentType = "text/unknown"; } notifyRequest.setContentType(contentType); notifyRequest.setBody(messageBody); UtlString request; ssize_t requestLength; notifyRequest.getBytes(&request, &requestLength); OsSysLog::add(FAC_SIP, PRI_DEBUG, "SipSubscribeServerEventHandler::getNotifyContent resourceId '%s', eventTypeKey '%s' contentType '%s' NOTIFY message length = %zu, message = '%s'", resourceId.data(), eventTypeKey.data(), contentType.data(), requestLength, request.data()); } return(gotBody); }
// Construct a MimeBodyPart from an HttpBody and a list of parameters. MimeBodyPart::MimeBodyPart(const HttpBody& httpBody, //< Provides the bytes of the body. const UtlDList& parameters //< Provides the parameters. ) : HttpBody(httpBody), mpParentBody(NULL), mParentBodyRawStartIndex(-1), mRawBodyLength(-1), mParentBodyStartIndex(-1), mBodyLength(-1) { // Copy the parameters to mNameValues. UtlDListIterator iterator(parameters); NameValuePair* nvp; while((nvp = (NameValuePair*) iterator())) { mNameValues.append(new NameValuePair(nvp->data(), nvp->getValue())); } // Add the Content-Type parameter, taken from the HttpBody. mNameValues.append(new NameValuePair(HTTP_CONTENT_TYPE_FIELD, httpBody.getContentType())); // Add the Content-Transfer-Encoding parameter. mNameValues.append(new NameValuePair(HTTP_CONTENT_TRANSFER_ENCODING_FIELD, HTTP_CONTENT_TRANSFER_ENCODING_BINARY)); // Members that reference the parent will be corrected later. }
void HttpRequestContext::extractPostCgiVariables(const HttpBody& body) { int length; UtlString bodyBytes; body.getBytes(&bodyBytes, &length); parseCgiVariables(bodyBytes.data()); bodyBytes.remove(0); }
// Dump the object's internal state. void PublishContentContainer::dumpState() { // indented 8 and 10 UtlString key(*this); key.replace(sizeof (CONTENT_KEY_SEPARATOR) - 1, key.index(CONTENT_KEY_SEPARATOR), " "); Os::Logger::instance().log(FAC_RLS, PRI_INFO, "\t PublishContentContainer %p UtlString = '%s'", this, data()); int index = 0; UtlSListIterator content_itor(mEventContent); HttpBody* body; while ((body = dynamic_cast <HttpBody*> (content_itor()))) { Os::Logger::instance().log(FAC_RLS, PRI_INFO, "\t mEventContent[%d] = '%s':'%s'", index, body->data(), body->getBytes()); index++; } }
// Dump the object's internal state. void PublishContentContainer::dumpState() { // indented 8 and 10 OsSysLog::add(FAC_RLS, PRI_INFO, "\t PublishContentContainer %p UtlString = '%s'", this, data()); int index = 0; UtlSListIterator content_itor(mEventContent); UtlSListIterator version_itor(mEventVersion); HttpBody* body; while ((body = dynamic_cast <HttpBody*> (content_itor()))) { UtlInt* version = dynamic_cast <UtlInt*> (version_itor()); OsSysLog::add(FAC_RLS, PRI_INFO, "\t mEventVersion[%d] = %" PRIdPTR ", " "mEventContent[%d] = '%s':'%s'", index, version->getValue(), index, body->data(), body->getBytes()); index++; } }
//! Generate the HttpBody for the current state of the resource list. HttpBody* ResourceList::generateRlmiBody(UtlBoolean consolidated, UtlBoolean fullRlmi, UtlSList& listToSend) { if (Os::Logger::instance().willLog(FAC_RLS, PRI_DEBUG)) { UtlString l; UtlSListIterator resourcesItor(listToSend); ResourceReference* resource; while ((resource = dynamic_cast <ResourceReference*> (resourcesItor()))) { l.append(*resource->getUri()); l.append(","); } if (!l.isNull()) { l.remove(l.length() - 1); } Os::Logger::instance().log(FAC_RLS, PRI_DEBUG, "ResourceList::generateRlmiBody cons=%d URI='%s' full=%d listToSend='%s'", consolidated, (consolidated ? mResourceListNameCons.data() : mResourceListName.data()), fullRlmi, l.data()); } // Construct the multipart body. // We add the <...> here, as they are used in all the contexts where // rlmiBodyPartCid appears. UtlString rlmiBodyPartCid; rlmiBodyPartCid += "<rlmi@"; rlmiBodyPartCid += getResourceListServer()->getDomainName(); rlmiBodyPartCid += ">"; UtlString content_type(CONTENT_TYPE_MULTIPART_RELATED ";type=\"" RLMI_CONTENT_TYPE "\"" ";start=\""); content_type += rlmiBodyPartCid; content_type += "\""; HttpBody* body = new HttpBodyMultipart(content_type); // This is the Resource List Meta-Information, XML describing the resources // and their instances. It is the main part of the NOTIFY body. UtlString rlmi; // Generate the initial part of the RLMI. rlmi += "<?xml version=\"1.0\"?>\r\n"; rlmi += "<list xmlns=\"" RLMI_XMLNS "\" uri=\""; XmlEscape(rlmi, consolidated ? mResourceListNameCons : mResourceListName); // Placeholder for version from SIP stack. rlmi += "\" version=\"" VERSION_PLACEHOLDER "\" "; // Generate either the full or the partial RLMI. if (fullRlmi) { rlmi += "fullState=\"true\">\r\n"; } else { rlmi += "fullState=\"false\">\r\n"; } // If we implemented names for resource lists, <name> elements would be added here. // Iterate through the resources. UtlSListIterator resourcesItor(listToSend); ResourceReference* resource; while ((resource = dynamic_cast <ResourceReference*> (resourcesItor()))) { // Add the content for the resource. resource->generateBody(rlmi, *body, consolidated); } // Generate the postamble for the resource list. rlmi += "</list>\r\n"; // Construct the RLMI body part. HttpBody rlmi_body(rlmi.data(), rlmi.length(), RLMI_CONTENT_TYPE); UtlDList rlmi_body_parameters; rlmi_body_parameters.append(new NameValuePair(HTTP_CONTENT_ID_FIELD, rlmiBodyPartCid)); // Attach the RLMI. body->appendBodyPart(rlmi_body, rlmi_body_parameters); // Clean up the parameter list. rlmi_body_parameters.destroyAll(); return body; }
// Add to the HttpBody the current state of the resource. void ResourceCached::generateBody(UtlString& rlmi, HttpBody& body, UtlBoolean consolidated, const UtlString& nameXml, const UtlString& displayName) const { // Generate the preamble for the resource. rlmi += " <resource uri=\""; XmlEscape(rlmi, *(static_cast <const UtlString*> (this))); rlmi += "\">\r\n"; if (!nameXml.isNull()) { rlmi += " "; rlmi += nameXml; } if (consolidated) { // If consolidating resource instances, generate the XML for the // unified resource instance. rlmi += " <instance id=\"consolidated\" state=\"active\""; UtlString contentBodyPartCid; // Use the count of parts in 'body' to generate a unique identifier for // each part. contentBodyPartCid.appendNumber(body.getMultipartCount()); contentBodyPartCid += "@"; contentBodyPartCid += getResourceListServer()->getDomainName(); rlmi += " cid=\""; rlmi += contentBodyPartCid; rlmi += "\""; // Now add the <...> and use it in the header. contentBodyPartCid.prepend("<"); contentBodyPartCid.append(">"); // Create a single HttpBody to contain the unified dialog event. UtlString dialog_event; // XML declaration is optional, but Broadworks uses it. dialog_event += "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"; dialog_event += BEGIN_DIALOG_INFO; dialog_event += VERSION_EQUAL; dialog_event += "\""; // The consolidated dialog events need to have persistent // version numbers, as they all have the same instance id. // So we use a global version number in the ResourceListSet. dialog_event.appendNumber(getResourceListSet()->getVersion()); dialog_event += "\""; dialog_event += STATE_EQUAL; dialog_event += "\"full\""; dialog_event += ENTITY_EQUAL; dialog_event += "\""; dialog_event += *(static_cast <const UtlString*> (this)); dialog_event += "\">\r\n"; // Save the length of dialog_event, so we can tell later if // any <dialog>s have been added to it. unsigned int preamble_length = dialog_event.length(); // Call the ContactSet to generate the consolidated dialog event body. if (mContactSetP) { mContactSetP->generateBody(dialog_event, body, consolidated, displayName); } // If no <dialog>s have been added, we have to add a dummy // <dialog> to carry the display name. if (dialog_event.length() == preamble_length) { dialog_event += "<dialog id=\";\"><state>terminated</state><local><identity display=\""; XmlEscape(dialog_event, displayName); dialog_event += "\">"; XmlEscape(dialog_event, *(static_cast <const UtlString*> (this))); dialog_event += "</identity></local></dialog>\r\n"; } dialog_event += END_DIALOG_INFO; // Insert the consolidated dialog event body into the multiplart body. HttpBody content_body(dialog_event.data(), dialog_event.length(), DIALOG_EVENT_CONTENT_TYPE); UtlDList content_body_parameters; content_body_parameters.append( new NameValuePair(HTTP_CONTENT_ID_FIELD, contentBodyPartCid)); body.appendBodyPart(content_body, content_body_parameters); content_body_parameters.destroyAll(); // Finish the <instance> element. rlmi += "/>\r\n"; } else { // Call the ContactSet to do the work. if (mContactSetP) { mContactSetP->generateBody(rlmi, body, consolidated, displayName); } } // Generate the postamble for the resource. rlmi += " </resource>\r\n"; }
// Add to the HttpBody the current state of the resource. void ResourceInstance::generateBody(UtlString& rlmi, HttpBody& body, UtlBoolean consolidated, const UtlString& displayName) const { OsSysLog::add(FAC_RLS, PRI_DEBUG, "ResourceInstance::generateBody mInstanceName = '%s', consolidated = %d, displayName = '%s', mContentPresent = %d", mInstanceName.data(), consolidated, displayName.data(), mContentPresent); if (consolidated) { if (mContentPresent) { // If this is a consolidated dialog event list, edit the // stored XML into the right form and append each dialog // to the resource list event notice. TiXmlUtlStringWriter writer(&rlmi); // Iterate through all the <dialog> elements. UtlHashMapIterator itor(mXmlDialogs); UtlContainable* id; while ((id = itor())) { UtlVoidPtr* p = dynamic_cast <UtlVoidPtr*> (itor.value()); TiXmlElement* dialog_element = static_cast <TiXmlElement*> (p->getValue()); // Now that we've got a <dialog> element, edit it to fit // into a consolidated event notice. // Get the display name right. // Find the <local> element, which we know exists due to // earlier processing. TiXmlNode* local = dialog_element->FirstChild("local"); // Find the <local><identity> element, which we know // exists due to earlier processing. TiXmlNode* identity = local->FirstChild("identity"); // Update the display attribute, as that is what will show // on the phone. identity->ToElement()-> SetAttribute("display", displayName); // Un-parse the dialog into the string for storage. writer << *dialog_element; writer << "\r\n"; } } } else { // Generate the XML for the instance. rlmi += " <instance id=\""; XmlEscape(rlmi, mInstanceName); rlmi += "\" state=\""; // Subscription states don't require escaping. rlmi += mSubscriptionState; rlmi += "\""; // Generate the body part for the instance, if necessary. if (mContentPresent) { UtlString contentBodyPartCid; // Use the count of parts in 'body' to generate a unique identifier for // each part. contentBodyPartCid.appendNumber(body.getMultipartCount()); contentBodyPartCid += "@"; contentBodyPartCid += getResourceListServer()->getDomainName(); rlmi += " cid=\""; rlmi += contentBodyPartCid; rlmi += "\""; // Now add the <...> and use it in the header. contentBodyPartCid.prepend("<"); contentBodyPartCid.append(">"); HttpBody content_body(mContent.data(), mContent.length(), getResourceListServer()->getContentType()); UtlDList content_body_parameters; content_body_parameters.append( new NameValuePair(HTTP_CONTENT_ID_FIELD, contentBodyPartCid)); body.appendBodyPart(content_body, content_body_parameters); content_body_parameters.destroyAll(); } rlmi += "/>\r\n"; } }
// Append a multipart body part to an existing multiparty body. void HttpBody::appendBodyPart(const HttpBody& body, const UtlDList& parameters) { assert(isMultipart()); // Construct a new MimeBodyPart for the new body part. MimeBodyPart* part = new MimeBodyPart(body, parameters); // Insert it as the last body part. mBodyParts.append(part); mBodyPartCount++; // Turn the final boundary into an intermediate boundary. mBody.remove(mBody.length() - 4); mBody.append("\r\n"); // Insert the headers. ssize_t rawPartStart = mBody.length(); UtlDListIterator iterator(*part->getParameters()); NameValuePair* nvp; while ((nvp = (NameValuePair*) iterator())) { mBody.append(nvp->data()); mBody.append(": "); mBody.append(nvp->getValue()); mBody.append("\r\n"); } mBody.append("\r\n"); // Insert the body. ssize_t partStart = mBody.length(); const char* bytes; ssize_t length; body.getBytes(&bytes, &length); mBody.append(bytes, length); ssize_t partEnd = mBody.length(); // Update bodyLength. bodyLength = mBody.length(); // Determine if we have to change the boundary string. bool change_boundary_string = mBody.index(mMultipartBoundary, partStart) != UTL_NOT_FOUND; // Add the final boundary. mBody.append("\r\n--"); mBody.append(mMultipartBoundary); mBody.append("--\r\n"); // Update the MimeBodyPart to know where it is contained in the HttpBody. part->attach(this, rawPartStart, partEnd - rawPartStart, partStart, partEnd - partStart); // If we have to change the boundary string. if (change_boundary_string) { // Find a new boundary string that isn't in the body. do { nextBoundary(mMultipartBoundary); } while (mBody.index(mMultipartBoundary) != UTL_NOT_FOUND); // Replace the old boundary string. UtlSListIterator iterator(mBodyParts); MimeBodyPart* part; while ((part = dynamic_cast<MimeBodyPart*>(iterator()))) { // Replace the boundary string just before this part. mBody.replace(part->getRawStart() - (2 + BOUNDARY_STRING_LENGTH), BOUNDARY_STRING_LENGTH, mMultipartBoundary.data(), BOUNDARY_STRING_LENGTH); } // Replace the boundary string in the final boundary. mBody.replace(mBody.length() - (4 + BOUNDARY_STRING_LENGTH), BOUNDARY_STRING_LENGTH, mMultipartBoundary.data(), BOUNDARY_STRING_LENGTH); // Replace the boundary string in the Content-Type. ssize_t loc = this->index(";" MULTIPART_BOUNDARY_PARAMETER "=\""); this->replace(loc + sizeof (";" MULTIPART_BOUNDARY_PARAMETER "=\"") - 1, BOUNDARY_STRING_LENGTH, mMultipartBoundary.data(), BOUNDARY_STRING_LENGTH); } }
UtlBoolean SipPublishContentMgr::getContent(const char* resourceId, const char* eventTypeKey, const char* eventType, UtlBoolean fullState, const UtlString& acceptHeaderValue, HttpBody*& content, UtlBoolean& isDefaultContent, UtlString* availableMediaTypes) { UtlBoolean foundContent = FALSE; PublishContentContainer* container = NULL; isDefaultContent = FALSE; UtlString key; key.append(resourceId); key.append(CONTENT_KEY_SEPARATOR); key.append(eventTypeKey); lock(); UtlHashBag* pContent; if (fullState) { // Full content (this is the usual case) pContent = &mContentEntries; } else { // Partial content (used for partial dialog events) pContent = &mPartialContentEntries; } // See if resource-specific content exists container = dynamic_cast <PublishContentContainer*> (pContent->find(&key)); // There is no resource-specific content. Check if the default // constructor exists. if (container == NULL) { // Construct the key for the default data. UtlString default_key; default_key.append(CONTENT_KEY_SEPARATOR); default_key.append(eventTypeKey); // Look up the constructor. UtlHashMap* pDefaultConstructors; if (fullState) { // Full content (this is the usual case) pDefaultConstructors = &mDefaultContentConstructors; } else { // Partial content (used for partial dialog events) pDefaultConstructors = &mDefaultPartialContentConstructors; } SipPublishContentMgrDefaultConstructor* constructor = dynamic_cast <SipPublishContentMgrDefaultConstructor*> (pDefaultConstructors->findValue(&default_key)); // If it exists, call it to publish content for this resource/event. if (constructor) { constructor->generateDefaultContent(this, resourceId, eventTypeKey, eventType); } // See if resource-specific content exists now. container = dynamic_cast <PublishContentContainer*> (pContent->find(&key)); // If content was found, still mark it as default content. if (container) { isDefaultContent = TRUE; } // If still no content was found, check if (fixed) default content exists. else { container = dynamic_cast <PublishContentContainer*> (mDefaultContentEntries.find(&default_key)); if(container) { isDefaultContent = TRUE; } } } // Within the container, choose the correct content. if (container) { if (acceptHeaderValue.compareTo(acceptAllTypes) != 0) { // Search for the first content in the container whose // MIME type is in the acceptable list. UtlSListIterator contentIterator(container->mEventContent); HttpBody* bodyPtr; while (!foundContent && (bodyPtr = dynamic_cast <HttpBody*> (contentIterator()))) { // Trim any parameters off the body content type. UtlString* content_type = bodyPtr; UtlString base_content_type(*content_type); ssize_t i = base_content_type.index(';'); if (i != UTL_NOT_FOUND) { base_content_type.remove(i); } // See if base_content_type is in acceptHeaderValue. if (acceptHeaderValue.findToken(base_content_type.data(), ",", ";")) { // If base_content_type is "multipart/related", extract // the 'type' parameter value, which is the type of the // root component, and check whether it is in acceptHeaderValue. ssize_t j; if (base_content_type.compareTo("multipart/related", UtlString::ignoreCase) == 0) { // Search for the 'type' parameter. i = content_type->index(";type=", UtlString::ignoreCase); if (i != UTL_NOT_FOUND) { // Advance i to point to the value. i += sizeof (";type=") - 1; if ((*content_type)(i) == '\"') { // Value is quoted. // Advance i to point to the value proper. i++; // Find the closing double-quote. j = content_type->index('\"', i); if (j == UTL_NOT_FOUND) { // This shouldn't happen. Os::Logger::instance().log(FAC_SIP, PRI_WARNING, "SipPublishContentMgr::getContent " "No closing double-quote found for 'type' parameter in body MIME type '%s'", content_type->data()); // j == UTL_NOT_FOUND indicates failure. } } else { // Value is not quoted. // Find the end of the parameter. j = content_type->index(';', i); if (j == UTL_NOT_FOUND) { j = content_type->length(); } } if (j != UTL_NOT_FOUND) { // Characters from i to j are the type parameter value. UtlString base_root_type; base_root_type.append(*content_type, i, j - i); // Remove parameters from base_root_type. ssize_t k = base_content_type.index(';'); if (k != UTL_NOT_FOUND) { base_content_type.remove(k); } // See if base_root_type is in acceptHeaderValue. if (acceptHeaderValue.findToken(base_root_type.data(), ",", ";")) { // Having passed all the tests, this content is OK. foundContent = true; } } } else { Os::Logger::instance().log(FAC_SIP, PRI_WARNING, "SipPublishContentMgr::getContent " "No 'type' parameter in body MIME type '%s'", content_type->data()); } } else { // If base_content_type is not multipart/related, // we can accept the content with no further tests. foundContent = true; } // If this content is acceptable, copy it into 'content'. // Because foundContent is true, the loop will exit. if (foundContent) { content = bodyPtr->copy(); } } } if (!foundContent) { // No content was found that matched the allowed MIME types. Os::Logger::instance().log(FAC_SIP, PRI_WARNING, "SipPublishContentMgr::getContent no acceptable content found for key '%s', acceptHeaderValue '%s', resourceId '%s', eventTypeKey ='%s', eventType '%s'", key.data(), acceptHeaderValue.data(), resourceId ? resourceId : "[none]", eventTypeKey, eventType); if (availableMediaTypes) { // Construct the list of available MIME types. availableMediaTypes->remove(0); contentIterator.reset(); while ((bodyPtr = dynamic_cast <HttpBody*> (contentIterator()))) { if (!availableMediaTypes->isNull()) { availableMediaTypes->append(','); } availableMediaTypes->append(static_cast <UtlString&> (*bodyPtr)); } } } } else { // No MIME types were specified, take the first content in the list. // (which should exist) HttpBody* bodyPtr = dynamic_cast <HttpBody*> (container->mEventContent.first()); if (bodyPtr) { content = bodyPtr->copy(); foundContent = TRUE; } else { // No content was found (at all). // Set *availableMediaTypes. if (availableMediaTypes) { availableMediaTypes->remove(0); } Os::Logger::instance().log(FAC_SIP, PRI_WARNING, "SipPublishContentMgr::getContent no content found for key '%s', resourceId '%s', eventTypeKey ='%s', eventType '%s' - publish() must have been called with numContentTypes==0", key.data(), resourceId ? resourceId : "[none]", eventTypeKey, eventType); } } } else { // No container found for this resource and event. // Set *availableMediaTypes. if (availableMediaTypes) { availableMediaTypes->remove(0); } Os::Logger::instance().log(FAC_SIP, PRI_WARNING, "SipPublishContentMgr::getContent no container found for key '%s', acceptHeaderValue '%s', resourceId '%s', eventTypeKey ='%s', eventType '%s', fullState = %d", key.data(), acceptHeaderValue.data(), resourceId ? resourceId : "[none]", eventTypeKey, eventType, fullState); } unlock(); return foundContent; }
int ParserCWHandler::getURL( const MC2String& urlStr, const MC2String& postData, uint32 peerIP, uint32 fromByte, uint32 toByte, LangTypes::language_t clientLang, const HttpHeader* inHeaders, HttpHeader& outHeaders, MC2String& reply, uint32& startByte, uint32& endByte ) { uint32 startTime = TimeUtility::getCurrentTime(); // Work with url MC2String serverURLStr( urlStr ); mc2dbg2 << "serverURLStr " << serverURLStr << endl; updateRequest( serverURLStr, clientLang ); bool fetchedThruProxy = false; if ( serverURLStr.find( "://sendThruProxyServer" ) != MC2String::npos ) { // This url should be fetched thru the proxy server // Remove 'sendThruProxyServer' from URL STLStringUtility::replaceString( serverURLStr, "://sendThruProxyServer/", "://" ); URL url(serverURLStr); HttpBody outBody; HttpVariableContainer myVar; myVar.https = ( serverURLStr.find( "https://" ) != MC2String::npos ); // Fetch the url thru proxy server. If proxy fails it will be fetched without // proxy below. fetchedThruProxy = HttpProxyFunctions::fetchThruProxy( url, &outHeaders, &outBody, m_thread, &myVar ); if ( fetchedThruProxy ) { // Successfully fetched thru proxy reply.append( outBody.getBody(), outBody.getBodyLength() ); } } // Work with url mc2dbg2 << "serverURLStr " << serverURLStr << endl; updateRequest( serverURLStr, clientLang ); URL url2( serverURLStr ); int ures = 0; uint32 timeout = Properties::getUint32Property( "CW_TIMEOUT", 5000 ); if ( ! fetchedThruProxy ) { if ( serverURLStr.find( "internalInThisProcess" ) != MC2String::npos ) { // Handle internally reply.clear(); if ( serverURLStr.find("/TMap/") != MC2String::npos ) { MC2String urlParam = STLStringUtility::basename( url2.getFile() ); if ( !urlParam.empty() ) { DataBuffer* d = m_thread->getTileMap( urlParam.c_str() ); if ( d != NULL ) { ures = 200; reply.append( reinterpret_cast<char*>( d->getBufferAddress() ), d->getCurrentOffset() ); outHeaders.setStartLine( 200 ); } else { outHeaders.setStartLine( 503 ); } delete d; } } } else { // Send request using the parserthreads urlfetcher URLFetcher* f = m_thread->getURLFetcher(); HttpHeader sendHeaders; // Extra headers to send // TODO: Add byterange using fromByte and toByte if not 0,MAX_UINT32 // so we don't download whole file all the time. MC2String peerIPstr = NetUtility::ip2str( peerIP ); sendHeaders.addHeaderLine( "X-Forwarded-For", peerIPstr ); static const MC2String notForwardHeadersStr[] = { "X-WAYF-CT", HttpHeaderLines::CONTENT_TYPE, HttpHeaderLines::CONTENT_LENGTH, HttpHeaderLines::CONNECTION, HttpHeaderLines::TRANSFER_ENCODING, HttpHeaderLines::X_FORWARDED_FOR, HttpHeaderLines::PROXY_CONNECTION, HttpHeaderLines::HOST, HttpHeaderLines::TE, HttpHeaderLines::TRAILER, HttpHeaderLines::KEEP_ALIVE, HttpHeaderLines::PROXY_AUTHENTICATE, HttpHeaderLines::PROXY_AUTHORIZATION, HttpHeaderLines::UPGRADE, }; // TODO: Also remove all headers in Connection: header. Like // "Connection: Keep-Alive, Trailer" should delete those two. static const set< MC2String, strNoCaseCompareLess > notForwardHeaders( BEGIN_ARRAY( notForwardHeadersStr ), END_ARRAY( notForwardHeadersStr ) ); if ( inHeaders != NULL ) { const HttpHeader::HeaderMap& headers = inHeaders->getHeaderMap(); for ( HttpHeader::HeaderMap::const_iterator it = headers.begin() ; it != headers.end() ; ++it ) { if ( notForwardHeaders.find( it->first ) == notForwardHeaders.end() ) { sendHeaders.addHeaderLine( it->first, *it->second ); } } } if ( postData.empty() ) { ures = f->get( reply, outHeaders, url2, timeout, &sendHeaders ); } else { if ( inHeaders->getHeaderValue( "X-WAYF-CT" ) != NULL ) { sendHeaders.addHeaderLine( HttpHeaderLines::CONTENT_TYPE, *inHeaders->getHeaderValue( "X-WAYF-CT" ) ); } else { sendHeaders.addHeaderLine( HttpHeaderLines::CONTENT_TYPE, "application/x-www-form-urlencoded" ); } ures = f->post( reply, outHeaders, url2, postData, timeout, &sendHeaders ); } // Reset user agent //f->setDefaultUserAgent(); } } // if (! fetchedThruProxy ) // Remove chunked-encoding from reply (if present) const MC2String teh( "Transfer-Encoding" ); const MC2String* te = outHeaders.getHeaderValue( &teh ); if ( te != NULL && ( te->find( "chunked") != MC2String::npos ) ) { outHeaders.deleteHeaderLine( &teh ); } // Check if web updated user const MC2String wfidh( "X-WFID-UPDATE" ); const MC2String* wfid = outHeaders.getHeaderValue( &wfidh ); if ( wfid != NULL ) { // Remove the uin from user cache uint32 uin = STLStringUtility::strtoul( *wfid ); m_group->removeUserFromCache( uin ); // And remove the header outHeaders.deleteHeaderLine( &wfidh ); } // Make reply const MC2String eol( "\r\n" ); if ( fromByte > toByte ) { toByte = fromByte; } const uint32 maxBytes = toByte - fromByte; uint32 lastByte = uint32( MAX( int32(reply.size()) - 1, 0 ) ); startByte = MIN( fromByte, lastByte ); endByte = startByte + MIN( lastByte - startByte, maxBytes ); if ( ures > 0 && reply.size() > 0 && (endByte != lastByte || startByte != 0) ) { // Set byte range in reply MC2String rangeStr( "bytes " ); STLStringUtility::uint2str( startByte, rangeStr ); rangeStr.append( "-" ); STLStringUtility::uint2str( endByte, rangeStr ); rangeStr.append( "/" ); STLStringUtility::uint2str( reply.size(), rangeStr ); // Real size outHeaders.addHeaderLine( "Content-Range", rangeStr ); rangeStr = ""; STLStringUtility::uint2str( endByte - startByte + 1, rangeStr ); // Set right content length outHeaders.addHeaderLine( "Content-Length", rangeStr ); // Set startline with 206 Partial Content MC2String responce( outHeaders.getStartLine()->substr( 0, 9 ) ); responce.append( "206 Partial Content" ); responce.append( eol ); outHeaders.setStartLine( new MC2String( responce ) ); } else if ( ures < 0 || outHeaders.getStartLine() == NULL ) { if ( TimeUtility::getCurrentTime() - startTime >= timeout ) { outHeaders.setStartLine( 503 ); } else { outHeaders.setStartLine( 500 ); } } else { // Set startline with eol outHeaders.setStartLine( new MC2String( StringUtility::trimStartEnd( *outHeaders.getStartLine() ) + eol ) ); } return ures; }
UtlBoolean SipPublishContentMgr::getContent(const char* resourceId, const char* eventTypeKey, const char* eventType, const char* acceptHeaderValue, HttpBody*& content, int& version, UtlBoolean& isDefaultContent, UtlBoolean fullState) { UtlBoolean foundContent = FALSE; UtlString key(resourceId); key.append(eventTypeKey); PublishContentContainer* container = NULL; isDefaultContent = FALSE; // Turn acceptHeaderValue into a HashBag of its components. // acceptedTypesGiven = FALSE if there are no components. UtlHashBag contentTypes; UtlBoolean acceptedTypesGiven = buildContentTypesContainer(acceptHeaderValue, contentTypes); lock(); UtlHashBag* pContent; if (fullState) { // Full content (this is the usual case) pContent = &mContentEntries; } else { // Partial content (used for partial dialog events) pContent = &mPartialContentEntries; } // See if resource-specific content exists container = dynamic_cast <PublishContentContainer*> (pContent->find(&key)); // There is no resource-specific content. Check if the default // constructor exists. if (container == NULL) { // Construct the key for the default data. UtlString default_key(eventTypeKey); // Look up the constructor. SipPublishContentMgrDefaultConstructor* constructor = dynamic_cast <SipPublishContentMgrDefaultConstructor*> (mDefaultContentConstructors.findValue(&default_key)); // If it exists, call it to publish content for this resource/event. if (constructor) { constructor->generateDefaultContent(this, resourceId, eventTypeKey, eventType); } // See if resource specific content exists now. container = dynamic_cast <PublishContentContainer*> (pContent->find(&key)); // If content was found, still mark it as default content. if (container) { isDefaultContent = TRUE; } // If still no content was found, check if the default exists. else { container = dynamic_cast <PublishContentContainer*> (mDefaultContentEntries.find(&default_key)); if(container) { isDefaultContent = TRUE; } } } // Within the container, find the content of the right MIME type. if (container) { if (acceptedTypesGiven) { UtlString base_mime_type; // Search for the first content in the container whose // MIME type is in the acceptable list. UtlSListIterator contentIterator(container->mEventContent); HttpBody* bodyPtr; UtlSListIterator versionIterator(container->mEventVersion); UtlInt* versionPtr; while (!foundContent && (bodyPtr = dynamic_cast <HttpBody*> (contentIterator())) && (versionPtr = dynamic_cast <UtlInt*> (versionIterator()))) { // Test if ';' is present in *bodyPtr's MIME type. // (Remember that an HttpBody considered as a UtlString has // the value of its content type.) ssize_t i = bodyPtr->index(';'); // The 'if expression' is TRUE if the MIME type of *bodyPtr // is found in in contentTypes. This is messy, because // *bodyPtr's MIME type may have parameters, which have // to be removed before searching contentTypes. if (contentTypes.find(i == UTL_NOT_FOUND ? bodyPtr : ( base_mime_type.remove(0), base_mime_type.append(*bodyPtr, 0, i), &base_mime_type))) { content = bodyPtr->copy(); version = versionPtr->getValue(); foundContent = TRUE; } } if (!foundContent) { // No content was found that matched the required MIME types. OsSysLog::add(FAC_SIP, PRI_WARNING, "SipPublishContentMgr::getContent no content found for key '%s', acceptHeaderValue '%s', resourceId '%s', eventTypeKey ='%s', eventType '%s'", key.data(), acceptHeaderValue ? acceptHeaderValue : "[none]", resourceId ? resourceId : "[none]", eventTypeKey, eventType); } } else { // No MIME types were specified, take the first content in the list. HttpBody* bodyPtr = dynamic_cast <HttpBody*> (container->mEventContent.first()); UtlInt* versionPtr = dynamic_cast <UtlInt*> (container->mEventVersion.first()); if (bodyPtr) { content = bodyPtr->copy(); version = versionPtr->getValue(); foundContent = TRUE; } else { // No content was found (at all). OsSysLog::add(FAC_SIP, PRI_WARNING, "SipPublishContentMgr::getContent no content found for key '%s', acceptHeaderValue '%s', resourceId '%s', eventTypeKey ='%s', eventType '%s'", key.data(), acceptHeaderValue ? acceptHeaderValue : "[none]", resourceId ? resourceId : "[none]", eventTypeKey, eventType); } } } else { // No container found for this resource and event. OsSysLog::add(FAC_SIP, PRI_WARNING, "SipPublishContentMgr::getContent no container found for key '%s', acceptHeaderValue '%s', resourceId '%s', eventTypeKey ='%s', eventType '%s', fullState = %d", key.data(), acceptHeaderValue ? acceptHeaderValue : "[none]", resourceId ? resourceId : "[none]", eventTypeKey, eventType, fullState); } unlock(); contentTypes.destroyAll(); return (foundContent); }