void SipDialog::reverseTags(const char* dialogHandle, UtlString& reversedHandle) { UtlString tag1; UtlString tag2; parseHandle(dialogHandle, reversedHandle, tag1, tag2); reversedHandle.capacity(strlen(dialogHandle) + 2); reversedHandle.append(DIALOG_HANDLE_SEPARATOR); reversedHandle.append(tag2); reversedHandle.append(DIALOG_HANDLE_SEPARATOR); reversedHandle.append(tag1); }
void Url::gen_value_escape(UtlString& unEscapedText) { // Check if there are any characters in unEscapedText that need to be // escaped in a field parameter value. if (strspn(unEscapedText.data(), // Alphanumerics "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" "0123456789" // Characters allowed in tokens "-.!%*_+`'~" // Additional characters allowed by the syntax of "host" "[]:") != unEscapedText.length()) { // Temporary string to construct the escaped value in. UtlString escapedText; // Pre-size it to the size of the un-escaped test, plus 2 for // the starting and ending double-quotes. escapedText.capacity((size_t) unEscapedText.length() + 2); const char* unescapedTextPtr = unEscapedText.data(); // Start with double-quote. escapedText.append("\""); // Process each character of the un-escaped value. while(*unescapedTextPtr) { char unEscapedChar = *unescapedTextPtr; if (unEscapedChar == '"' || unEscapedChar == '\\') { // Construct a little 2-character string and append it. char escapedChar[2]; escapedChar[0] = '\\'; escapedChar[1] = *unescapedTextPtr; escapedText.append(&unEscapedChar, 2); } else { // Append the character directly. escapedText.append(&unEscapedChar, 1); } // Consider the next character. unescapedTextPtr++; } // End with double-quote. escapedText.append("\""); // Write the escaped string into the argumemt. unEscapedText = escapedText; } }
/* //////////////////////////// PRIVATE /////////////////////////////////// */ UtlString LogNotifier::escape(const UtlString& source) { UtlString results; const char* pStart = source.data() ; const char* pTraverse = pStart ; const char* pLast = pStart ; results.capacity(source.length() + 100); while (*pTraverse) { switch (*pTraverse) { case '\\': // Copy old data if (pLast < pTraverse) { results.append(pLast, pTraverse-pLast); } pLast = pTraverse + 1 ; // Add escaped Text results.append("\\\\") ; break ; case '\r': // Copy old data if (pLast < pTraverse) { results.append(pLast, pTraverse-pLast); } pLast = pTraverse + 1 ; // Add escaped Text results.append("\\r") ; break ; case '\n': // Copy old data if (pLast < pTraverse) { results.append(pLast, pTraverse-pLast); } pLast = pTraverse + 1 ; // Add escaped Text results.append("\\n") ; break ; case '\"': // Copy old data if (pLast < pTraverse) { results.append(pLast, pTraverse-pLast); } pLast = pTraverse + 1 ; // Add escaped Text results.append("\\\"") ; break ; default: break ; } pTraverse++ ; } // if nothing to escape, short-circuit if (pLast == pStart) { return source ; } else if (pLast < pTraverse) { results.append(pLast, pTraverse-pLast); } return results ; }
void HttpFileAccess::sendFile(const UtlString& path, const UtlString& peerName, const HttpRequestContext& requestContext, const HttpMessage& request, HttpMessage*& response ) { UtlString message; int file = open(path.data(), O_RDONLY); if (0 <= file) { UtlString fileBuffer; if (fileBuffer.capacity(MAX_FILE_CHUNK_SIZE + 1) >= MAX_FILE_CHUNK_SIZE + 1) { response->setResponseFirstHeaderLine(HTTP_PROTOCOL_VERSION_1_1, HTTP_OK_CODE, HTTP_OK_TEXT); response->useChunkedBody(true); // @TODO Annotate file resources with a mime type? // add a Content-Disposition header to suggest saving as the basename of the file response->setContentType("application/octet-stream"); UtlString dispositionValue; UtlString basename; ssize_t finalSlash = path.last('/'); if (UTL_NOT_FOUND != finalSlash) { basename.append(path, finalSlash+1, path.length()-finalSlash); } else { basename.append(path); // don't think this should ever be true.... } dispositionValue.append("attachment; filename=\""); dispositionValue.append(basename); dispositionValue.append("\""); response->setHeaderValue(HTTP_CONTENT_DISPOSITION_FIELD,dispositionValue.data()); bool writtenOk = response->writeHeaders(requestContext.socket()); ssize_t bytes; Int64 totalBytes = 0; Int64 chunks = 0; while ( writtenOk && (bytes = read(file, (void*)fileBuffer.data(), MAX_FILE_CHUNK_SIZE))) { fileBuffer.setLength(bytes); writtenOk = response->writeChunk(requestContext.socket(), fileBuffer); if (writtenOk) { totalBytes += bytes; chunks++; } OsSysLog::add(FAC_SUPERVISOR, PRI_DEBUG, "file block %"FORMAT_INTLL"d %zd %s", chunks, bytes, writtenOk ? "ok" : "failed"); } if (writtenOk) { response->writeEndOfChunks(requestContext.socket()); message.append(" sent file '"); message.append(path); message.append("' ("); message.appendNumber(totalBytes,"%"FORMAT_INTLL"d"); message.append(" bytes in "); message.appendNumber(chunks,"%"FORMAT_INTLL"d"); message.append(" chunks) to peer "); message.append(peerName); OsSysLog::add(FAC_SUPERVISOR, PRI_INFO, "HttpFileAccess::processRequest %s", message.data()); } else { message.append("error writing response after "); message.appendNumber(totalBytes,"%"FORMAT_INTLL"d"); message.append(" body bytes in "); message.appendNumber(chunks,"%"FORMAT_INTLL"d"); message.append(" chunks) to peer "); message.append(peerName); OsSysLog::add(FAC_SUPERVISOR, PRI_ERR, "HttpFileAccess::processRequest %s", message.data()); } /* * We've already written the response, so prevent HttpServer from sending it by * not passing it back. */ delete response; response = NULL; } else { // Send out-of-resources message message.append("Supervisor Buffer Exhausted"); response->setResponseFirstHeaderLine(HTTP_PROTOCOL_VERSION, HTTP_OUT_OF_RESOURCES_CODE, message.data()); response->setContentType(CONTENT_TYPE_TEXT_PLAIN); response->setBody(new HttpBody(message.data(),message.length())); response->setContentLength(message.length()); OsSysLog::add(FAC_SUPERVISOR, PRI_ERR, "HttpFileAccess::processRequest from %s %s", peerName.data(), message.data()); } } else { int httpStatusCode; UtlString httpStatusText; switch (errno) { case EACCES: httpStatusCode = HTTP_FORBIDDEN_CODE; httpStatusText = "File Access Denied"; break; case ENOENT: httpStatusCode = HTTP_FILE_NOT_FOUND_CODE; httpStatusText = HTTP_FILE_NOT_FOUND_TEXT; break; default: httpStatusCode = HTTP_SERVER_ERROR_CODE; httpStatusText = HTTP_SERVER_ERROR_TEXT; break; } message.append("File '"); message.append(path); message.append("' errno "); message.appendNumber(errno); message.append(" "); char errnoMsg[1024]; strerror_r(errno, errnoMsg, sizeof(errnoMsg)); message.append(errnoMsg); OsSysLog::add(FAC_SUPERVISOR, PRI_ERR, "HttpFileAccess::processRequest from %s %s", peerName.data(), message.data()); response->setResponseFirstHeaderLine(HTTP_PROTOCOL_VERSION, httpStatusCode, httpStatusText); response->setBody(new HttpBody(message.data(),message.length())); response->setContentType(CONTENT_TYPE_TEXT_PLAIN); response->setContentLength(message.length()); } }
/** * The contents of the source string are appended to the destination string, with all * characters escaped as described above. * @returns true for success, false if an error was returned from any UtlString operation. */ bool XmlEscape(UtlString& destination, const UtlString& source) { bool resultOk = false; size_t srcLen = source.length(); if (srcLen > 0) { // make sure that the destination is at least large enough to add the source size_t minDstLen = destination.length() + srcLen; if (destination.capacity(minDstLen) >= minDstLen) { RegEx copyChars(CopyChars); UtlString escapeChar; bool matched; // each iteration picks up leading n valid chars (n may be zero) and one that needs to be escaped. for (matched = copyChars.Search(source.data(), srcLen); matched; matched = copyChars.SearchAgain() ) { // copy any leading characters that don't need to be escaped copyChars.MatchString(&destination,1); if (copyChars.MatchString(&escapeChar,2)) // was there an escaped character? { switch(*escapeChar.data()) { case '\x22' /* " */: destination.append(QUOTE); break; case '\x26' /* & */: destination.append(AMPERSAND); break; case '\x27' /* ' */: destination.append(APOSTROPHE); break; case '\x3c' /* < */: destination.append(LESS_THAN); break; case '\x3e' /* > */: destination.append(GREATER_THAN); break; default: { // outside the valid range; escape as numeric entity char hexval[7]; sprintf(hexval, "&#x%02x;", *escapeChar.data()); destination.append(hexval); } break; } escapeChar.remove(0); // clear for next iteration } } resultOk = true; } else { // UtlString capacity failed assert(false); } } else { resultOk = true; // empty source - easy } return resultOk; }
/** * The contents of the source string are appended to the destination string, with all * characters unescaped as described above. * @returns true for success, false if an error was returned from any UtlString operation. */ bool XmlUnEscape(UtlString& destination, const UtlString& source) { bool resultOk = false; size_t srcLen = source.length(); if (srcLen > 0) { // make sure that the destination is large enough to add the source (which cannot grow) size_t minDstLen = destination.length() + srcLen; if (destination.capacity(minDstLen) >= minDstLen) { RegEx entity(Entity); UtlString number; bool matched; bool matchedOnce; bool firstMatch = true; // each iteration picks up leading n valid chars (n may be zero) and one that needs to be escaped. for (matchedOnce = matched = entity.Search(source.data(), srcLen); matched; matched = entity.SearchAgain() ) { if (firstMatch) { // copy any leading characters that don't need to be escaped entity.BeforeMatchString(&destination); firstMatch = false; } if (entity.MatchString(NULL,1)) { destination.append('"'); } else if (entity.MatchString(NULL,2)) { destination.append('&'); } else if (entity.MatchString(NULL,3)) { destination.append("'"); } else if (entity.MatchString(NULL,4)) { destination.append('<'); } else if (entity.MatchString(NULL,5)) { destination.append('>'); } else if (entity.MatchString(&number,6)) { char* unconverted; int decimalNum = strtol(number.data(), &unconverted, /* base */ 10); if ('\000'==*unconverted && decimalNum >= 0 && decimalNum < 256) { destination.append(decimalNum); } else { // invalid decimal numeric entity - transcribe it untranslated destination.append(number); } number.remove(0); // clear for next iteration } else if (entity.MatchString(&number,7)) { char* unconverted; int decimalNum = strtol(number.data(), &unconverted, /* base */ 16); if ('\000'==*unconverted && decimalNum >= 0 && decimalNum < 256) { destination.append(decimalNum); } else { // invalid decimal numeric entity - transcribe it untranslated destination.append(number); } number.remove(0); // clear for next iteration } else { assert(false); // the Entity expression should have matched one of the above } // copy any leading characters that don't need to be escaped entity.MatchString(&destination,8); } if (!matchedOnce) { // there were no entities, so just copy the content. destination.append(source); } resultOk = true; } else { // UtlString capacity failed assert(false); } } else { resultOk = true; // empty source - easy } return resultOk; }