Regex::Result Regex::MatchOne(const StringPiece &text) { if (!impl || !text.len) return Regex::Result(); auto compiled = static_cast<std::regex*>(impl); std::match_results<const char*> matches; if (!std::regex_search(text.begin(), text.end(), matches, *compiled) || matches.size() < 2) return Regex::Result(); return Regex::Result(matches[1].first - text.begin(), matches[1].second - text.begin()); }
bool hasPCREPatternMatch(StringPiece pattern, StringPiece target) { return boost::regex_match( target.begin(), target.end(), boost::regex(pattern.begin(), pattern.end()) ); }
StringPiece LogName::getParent(StringPiece name) { if (name.empty()) { return name; } ssize_t idx = name.size(); // Skip over any trailing separator characters while (idx > 0 && isSeparator(name[idx - 1])) { --idx; } // Now walk backwards to the next separator character while (idx > 0 && !isSeparator(name[idx - 1])) { --idx; } // And again skip over any separator characters, in case there are multiple // repeated characters. while (idx > 0 && isSeparator(name[idx - 1])) { --idx; } return StringPiece(name.begin(), idx); }
TreeFragmentTokenizer::TreeFragmentTokenizer(const StringPiece &s) : str_(s) , value_(TreeFragmentToken_EOS, "", -1) , iter_(s.begin()) , end_(s.end()) , pos_(0) { ++(*this); }
void Item::resetKey(StringPiece k) { assert(k.size() <= 250); keylen_ = k.size(); receivedBytes_ = 0; append(k.data(), k.size()); hash_ = boost::hash_range(k.begin(), k.end()); }
Uri::Uri(StringPiece str) : port_(0) { static const boost::regex uriRegex( "([a-zA-Z][a-zA-Z0-9+.-]*):" // scheme: "([^?#]*)" // authority and path "(?:\\?([^#]*))?" // ?query "(?:#(.*))?"); // #fragment static const boost::regex authorityAndPathRegex("//([^/]*)(/.*)?"); boost::cmatch match; if (UNLIKELY(!boost::regex_match(str.begin(), str.end(), match, uriRegex))) { throw std::invalid_argument(to<std::string>("invalid URI ", str)); } scheme_ = submatch(match, 1); toLower(scheme_); StringPiece authorityAndPath(match[2].first, match[2].second); boost::cmatch authorityAndPathMatch; if (!boost::regex_match(authorityAndPath.begin(), authorityAndPath.end(), authorityAndPathMatch, authorityAndPathRegex)) { // Does not start with //, doesn't have authority path_ = authorityAndPath.fbstr(); } else { static const boost::regex authorityRegex( "(?:([^@:]*)(?::([^@]*))?@)?" // username, password "(\\[[^\\]]*\\]|[^\\[:]*)" // host (IP-literal (e.g. '['+IPv6+']', // dotted-IPv4, or named host) "(?::(\\d*))?"); // port auto authority = authorityAndPathMatch[1]; boost::cmatch authorityMatch; if (!boost::regex_match(authority.first, authority.second, authorityMatch, authorityRegex)) { throw std::invalid_argument( to<std::string>("invalid URI authority ", StringPiece(authority.first, authority.second))); } StringPiece port(authorityMatch[4].first, authorityMatch[4].second); if (!port.empty()) { port_ = to<uint16_t>(port); } username_ = submatch(authorityMatch, 1); password_ = submatch(authorityMatch, 2); host_ = submatch(authorityMatch, 3); path_ = submatch(authorityAndPathMatch, 2); } query_ = submatch(match, 3); fragment_ = submatch(match, 4); }
Item::Item(StringPiece keyArg, uint32_t flagsArg, int exptimeArg, int valuelen, uint64_t casArg) : keylen_(keyArg.size()), flags_(flagsArg), rel_exptime_(exptimeArg), valuelen_(valuelen), receivedBytes_(0), cas_(casArg), hash_(boost::hash_range(keyArg.begin(), keyArg.end())), data_(static_cast<char*>(::malloc(totalLen()))) { assert(valuelen_ >= 2); assert(receivedBytes_ < totalLen()); append(keyArg.data(), keylen_); }
void MacAddress::parse(StringPiece str) { // Helper function to convert a single hex char into an integer auto unhex = [](char c) -> int { return c >= '0' && c <= '9' ? c - '0' : c >= 'A' && c <= 'F' ? c - 'A' + 10 : c >= 'a' && c <= 'f' ? c - 'a' + 10 : -1; }; auto isSeparatorChar = [](char c) { return c == ':' || c == '-'; }; uint8_t parsed[SIZE]; auto p = str.begin(); for (unsigned int byteIndex = 0; byteIndex < SIZE; ++byteIndex) { if (p == str.end()) { throw invalid_argument(to<string>("invalid MAC address \"", str, "\": not enough digits")); } // Skip over ':' or '-' separators between bytes if (byteIndex != 0 && isSeparatorChar(*p)) { ++p; if (p == str.end()) { throw invalid_argument(to<string>("invalid MAC address \"", str, "\": not enough digits")); } } // Parse the upper nibble int upper = unhex(*p); if (upper < 0) { throw invalid_argument(to<string>("invalid MAC address \"", str, "\": contains non-hex digit")); } ++p; // Parse the lower nibble int lower; if (p == str.end()) { lower = upper; upper = 0; } else { lower = unhex(*p); if (lower < 0) { // Also accept ':', '-', or '\0', to handle the case where one // of the bytes was represented by just a single digit. if (isSeparatorChar(*p)) { lower = upper; upper = 0; } else { throw invalid_argument(to<string>("invalid MAC address \"", str, "\": contains non-hex digit")); } } ++p; } // Update parsed with the newly parsed byte parsed[byteIndex] = ((upper << 4) | lower); } if (p != str.end()) { // String is too long to be a MAC address throw invalid_argument(to<string>("invalid MAC address \"", str, "\": found trailing characters")); } // Only update now that we have successfully parsed the entire // string. This way we remain unchanged on error. setFromBinary(ByteRange(parsed, SIZE)); }
bool Session::processRequest(StringPiece request) { assert(command_.empty()); assert(!noreply_); assert(policy_ == Item::kInvalid); assert(!currItem_); assert(bytesToDiscard_ == 0); ++requestsProcessed_; // check 'noreply' at end of request line if (request.size() >= 8) { StringPiece end(request.end() - 8, 8); if (end == " noreply") { noreply_ = true; request.remove_suffix(8); } } SpaceSeparator sep; Tokenizer tok(request.begin(), request.end(), sep); Tokenizer::iterator beg = tok.begin(); if (beg == tok.end()) { reply("ERROR\r\n"); return true; } (*beg).CopyToString(&command_); ++beg; if (command_ == "set" || command_ == "add" || command_ == "replace" || command_ == "append" || command_ == "prepend" || command_ == "cas") { // this normally returns false return doUpdate(beg, tok.end()); } else if (command_ == "get" || command_ == "gets") { bool cas = command_ == "gets"; // FIXME: send multiple chunks with write complete callback. while (beg != tok.end()) { StringPiece key = *beg; bool good = key.size() <= kLongestKeySize; if (!good) { reply("CLIENT_ERROR bad command line format\r\n"); return true; } needle_->resetKey(key); ConstItemPtr item = owner_->getItem(needle_); ++beg; if (item) { item->output(&outputBuf_, cas); } } outputBuf_.append("END\r\n"); if (conn_->outputBuffer()->writableBytes() > 65536 + outputBuf_.readableBytes()) { LOG_DEBUG << "shrink output buffer from " << conn_->outputBuffer()->internalCapacity(); conn_->outputBuffer()->shrink(65536 + outputBuf_.readableBytes()); } conn_->send(&outputBuf_); } else if (command_ == "delete") { doDelete(beg, tok.end()); } else if (command_ == "version") { #ifdef HAVE_TCMALLOC reply("VERSION 0.01 muduo with tcmalloc\r\n"); #else reply("VERSION 0.01 muduo\r\n"); #endif } #ifdef HAVE_TCMALLOC else if (command_ == "memstat") { char buf[1024 * 64]; MallocExtension::instance()->GetStats(buf, sizeof buf); reply(buf); } #endif else if (command_ == "quit") { conn_->shutdown(); } else if (command_ == "shutdown") { // "ERROR: shutdown not enabled" conn_->shutdown(); owner_->stop(); } else { reply("ERROR\r\n"); LOG_INFO << "Unknown command: " << command_; } return true; }