| /* |
| * Copyright 2012 Google Inc. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| // Author: mukerjee@google.com (Matt Mukerjee) |
| |
| #include "net/instaweb/rewriter/public/experiment_matcher.h" |
| |
| #include "net/instaweb/rewriter/public/experiment_util.h" |
| #include "net/instaweb/rewriter/public/rewrite_options.h" |
| #include "pagespeed/kernel/base/basictypes.h" // for int64 |
| |
| namespace net_instaweb { |
| |
| ExperimentMatcher::~ExperimentMatcher() { } |
| |
| bool ExperimentMatcher::ClassifyIntoExperiment( |
| const RequestHeaders& headers, const UserAgentMatcher& agent_matcher, |
| RewriteOptions* options) { |
| bool need_cookie; |
| int experiment_value = experiment::kExperimentNotSet; |
| experiment::GetExperimentCookieState(headers, &experiment_value); |
| |
| if (options->enroll_experiment_id() == experiment::kExperimentNotSet) { |
| // Forcing kExperimentNotSet means "reassign this user". While normally we |
| // don't set any cookies if all percentages are 0%, here we do because they |
| // may be trying to clear a test cookie for a 0% experiment. |
| experiment_value = |
| experiment::DetermineExperimentState(options, headers, agent_matcher); |
| need_cookie = true; |
| } else if ( |
| options->enroll_experiment_id() == experiment::kNoExperiment || |
| options->GetExperimentSpec(options->enroll_experiment_id()) != NULL) { |
| // Only allow people to force experiment ids that are actually defined |
| // plus kNoExperiment. |
| experiment_value = options->enroll_experiment_id(); |
| need_cookie = true; |
| } else if (experiment_value == experiment::kNoExperiment) { |
| // TODO(jefftk): They're assigned to the control group, but we don't handle |
| // this right because we don't know if the cookie is stale. For example, |
| // they may have run one experiment on 5% of visitors and now be running one |
| // on 50% but that 95% who originally got put into "No-Experiment" |
| // (PageSpeedExperiment=0) will be excluded until their cookies expire. |
| need_cookie = false; |
| } else if (options->GetExperimentSpec(experiment_value) == NULL) { |
| // Either: |
| // * They're not yet assigned to an experiment grouping. |
| // * They were assigned, but that experiment isn't running anymore. |
| // |
| // Only set cookies if there are active experiments. This avoids the |
| // problem where when someone is preparing to run experiments by testing |
| // configuration on a live site all the visitors start getting put in the |
| // "no experiment" group. Not only does that reduce the sample available |
| // for experimentation, but it adds a bias away from repeat visitors. |
| if (experiment::AnyActiveExperiments(options)) { |
| experiment_value = |
| experiment::DetermineExperimentState(options, headers, agent_matcher); |
| need_cookie = true; |
| } else { |
| need_cookie = false; |
| } |
| } else { |
| // They're in an experiment, there's nothing wrong with it, all is well. |
| need_cookie = false; |
| } |
| |
| options->SetExperimentState(experiment_value); |
| return need_cookie; |
| } |
| |
| void ExperimentMatcher::StoreExperimentData( |
| int state, const StringPiece& url, int64 expiration_time_ms, |
| ResponseHeaders* headers) { |
| experiment::SetExperimentCookie(headers, state, url, expiration_time_ms); |
| } |
| |
| |
| } // namespace net_instaweb |