当前位置: 首页 > article >正文

Chromium form表单post提交过程分析c++

form表单get提交参考之前文章Chromium 前端form表单提交过程分析c++-CSDN博客

一、表单post提交测试例子:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"> 
<title>菜鸟教程(runoob.com)</title> 
</head>
<body>

    <h2>表单</h2>

    <form action="/" method="post">
        <!-- 文本输入框 -->
        <label for="name">用户名:</label>
        <input type="text" id="name" name="name" required>

        <br>

        <!-- 密码输入框 -->
        <label for="password">密码:</label>
        <input type="password" id="password" name="password" required>

        <br>

        <!-- 单选按钮 -->
        <label>性别:</label>
        <input type="radio" id="male" name="gender" value="male" checked>
        <label for="male">男</label>
        <input type="radio" id="female" name="gender" value="female">
        <label for="female">女</label>

        <br>

        <!-- 复选框 -->
        <input type="checkbox" id="subscribe" name="subscribe" checked>
        <label for="subscribe">订阅推送信息</label>

        <br>

        <!-- 下拉列表 -->
        <label for="country">国家:</label>
        <select id="country" name="country">
            <option value="cn">CN</option>
            <option value="usa">USA</option>
            <option value="uk">UK</option>
        </select>

        <br>

        <!-- 提交按钮 -->
        <input type="submit" value="提交">
    </form>

</body>
</html>

二、启动调试打开测试页:

    在\src\third_party\blink\renderer\core\loader\form_submission.cc 

FormSubmission::Create函数打断点:

 1.1)、 FormSubmission::Attributes copied_attributes;
              copied_attributes.CopyFrom(attributes);

获取前端:

名称类型
copied_attributes{method_=kPostMethod (1) is_multi_part_form_=false action_=[1] "/" ...}blink::FormSubmission::Attributes
method_kPostMethod (1)blink::FormSubmission::SubmitMethod
is_multi_part_form_falsebool
▶ action_[1] "/"WTF::String
▶ target_(null)WTF::AtomicString
▶ encoding_type_[33] "application/x-www-form-urlencoded"WTF::AtomicString
▶ accept_charset_(null)WTF::String

1.2)、  FormData* dom_form_data = form->ConstructEntryList(
      submit_button, data_encoding.EncodingForFormSubmission());
  DCHECK(dom_form_data);函数遍历form表单input属性 构建key=value

1.3)、调用form_data = dom_form_data->EncodeFormData()进行EncodeFormData

1.4)、将构造好的数据form_data设置到请求body里面:

    resource_request->SetHttpMethod(http_names::kPOST);
    resource_request->SetHttpBody(form_data);

看下设置到body中的值:

名称类型
form_body.ptr_->elements_.buffer_[0].data_[60] 0x000005500040df40 "name"...WTF::Vector<char,0,WTF::PartitionAllocator>

 

form_body.ptr_->elements_.buffer_[0].data_内存地址0x000005500040df40对应值如下:

已经将刚才填写的内容设置到body。 

 三、wireshark抓包验证:

可以看到和调试的一样结果:

四、结论:

1.application/x-www-form-urlencoded

  1. GET方式,会将表单中的数据(键值对)经过urlencode编码后追加到url中。
  2. POST方式,会将表单中的数据经过urlencode编码后放在request body 中。

2.multipart/form-data

当需要在表单内上传文件时(二进制流数据)时,就需要使用 multipart/form-data。

 附:FormSubmission::Create函数定义如下

FormSubmission* FormSubmission::Create(HTMLFormElement* form,
                                       const Attributes& attributes,
                                       const Event* event,
                                       HTMLFormControlElement* submit_button) {
  DCHECK(form);

  FormSubmission::Attributes copied_attributes;
  copied_attributes.CopyFrom(attributes);
  if (submit_button) {
    AtomicString attribute_value;
    if (!(attribute_value =
              submit_button->FastGetAttribute(html_names::kFormactionAttr))
             .IsNull())
      copied_attributes.ParseAction(attribute_value);
    if (!(attribute_value =
              submit_button->FastGetAttribute(html_names::kFormenctypeAttr))
             .IsNull())
      copied_attributes.UpdateEncodingType(attribute_value);
    if (!(attribute_value =
              submit_button->FastGetAttribute(html_names::kFormmethodAttr))
             .IsNull())
      copied_attributes.UpdateMethodType(attribute_value);
    if (!(attribute_value =
              submit_button->FastGetAttribute(html_names::kFormtargetAttr))
             .IsNull())
      copied_attributes.SetTarget(attribute_value);
  }

  if (copied_attributes.Method() == kDialogMethod) {
    if (submit_button) {
      return MakeGarbageCollected<FormSubmission>(
          submit_button->ResultForDialogSubmit());
    }
    return MakeGarbageCollected<FormSubmission>("");
  }

  Document& document = form->GetDocument();
  KURL action_url = document.CompleteURL(copied_attributes.Action().empty()
                                             ? document.Url().GetString()
                                             : copied_attributes.Action());

  if ((document.domWindow()->GetSecurityContext().GetInsecureRequestPolicy() &
       mojom::blink::InsecureRequestPolicy::kUpgradeInsecureRequests) !=
          mojom::blink::InsecureRequestPolicy::kLeaveInsecureRequestsAlone &&
      action_url.ProtocolIs("http") &&
      !network::IsUrlPotentiallyTrustworthy(GURL(action_url))) {
    UseCounter::Count(document,
                      WebFeature::kUpgradeInsecureRequestsUpgradedRequestForm);
    action_url.SetProtocol("https");
    if (action_url.Port() == 80)
      action_url.SetPort(443);
  }

  bool is_mailto_form = action_url.ProtocolIs("mailto");
  bool is_multi_part_form = false;
  AtomicString encoding_type = copied_attributes.EncodingType();

  if (copied_attributes.Method() == kPostMethod) {
    is_multi_part_form = copied_attributes.IsMultiPartForm();
    if (is_multi_part_form && is_mailto_form) {
      encoding_type = AtomicString("application/x-www-form-urlencoded");
      is_multi_part_form = false;
    }
  }
  WTF::TextEncoding data_encoding =
      is_mailto_form
          ? UTF8Encoding()
          : FormDataEncoder::EncodingFromAcceptCharset(
                copied_attributes.AcceptCharset(), document.Encoding());
  FormData* dom_form_data = form->ConstructEntryList(
      submit_button, data_encoding.EncodingForFormSubmission());
  DCHECK(dom_form_data);

  scoped_refptr<EncodedFormData> form_data;
  String boundary;

  if (is_multi_part_form) {
    form_data = dom_form_data->EncodeMultiPartFormData();
    boundary = form_data->Boundary().data();
  } else {
    form_data = dom_form_data->EncodeFormData(
        attributes.Method() == kGetMethod
            ? EncodedFormData::kFormURLEncoded
            : EncodedFormData::ParseEncodingType(encoding_type));
    if (copied_attributes.Method() == kPostMethod && is_mailto_form) {
      // Convert the form data into a string that we put into the URL.
      AppendMailtoPostFormDataToURL(action_url, *form_data, encoding_type);
      form_data = EncodedFormData::Create();
    }
  }

  form_data->SetIdentifier(GenerateFormDataIdentifier());
  form_data->SetContainsPasswordData(dom_form_data->ContainsPasswordData());

  if (copied_attributes.Method() != FormSubmission::kPostMethod &&
      !action_url.ProtocolIsJavaScript()) {
    action_url.SetQuery(form_data->FlattenToString());
  }

  std::unique_ptr<ResourceRequest> resource_request =
      std::make_unique<ResourceRequest>(action_url);
  ClientNavigationReason reason = ClientNavigationReason::kFormSubmissionGet;
  if (copied_attributes.Method() == FormSubmission::kPostMethod) {
    reason = ClientNavigationReason::kFormSubmissionPost;
    resource_request->SetHttpMethod(http_names::kPOST);
    resource_request->SetHttpBody(form_data);

    // construct some user headers if necessary
    if (boundary.empty()) {
      resource_request->SetHTTPContentType(encoding_type);
    } else {
      resource_request->SetHTTPContentType(encoding_type +
                                           "; boundary=" + boundary);
    }
  }
  resource_request->SetHasUserGesture(
      LocalFrame::HasTransientUserActivation(form->GetDocument().GetFrame()));
  resource_request->SetFormSubmission(true);

  mojom::blink::TriggeringEventInfo triggering_event_info;
  if (event) {
    triggering_event_info =
        event->isTrusted()
            ? mojom::blink::TriggeringEventInfo::kFromTrustedEvent
            : mojom::blink::TriggeringEventInfo::kFromUntrustedEvent;
    if (event->UnderlyingEvent())
      event = event->UnderlyingEvent();
  } else {
    triggering_event_info = mojom::blink::TriggeringEventInfo::kNotFromEvent;
  }

  FrameLoadRequest frame_request(form->GetDocument().domWindow(),
                                 *resource_request);
  NavigationPolicy navigation_policy = NavigationPolicyFromEvent(event);
  if (navigation_policy == kNavigationPolicyLinkPreview) {
    return nullptr;
  }
  frame_request.SetNavigationPolicy(navigation_policy);
  frame_request.SetClientRedirectReason(reason);
  if (submit_button) {
    frame_request.SetSourceElement(submit_button);
  } else {
    frame_request.SetSourceElement(form);
  }
  frame_request.SetTriggeringEventInfo(triggering_event_info);
  AtomicString target_or_base_target = frame_request.CleanNavigationTarget(
      copied_attributes.Target().empty() ? document.BaseTarget()
                                         : copied_attributes.Target());

  if (form->HasRel(HTMLFormElement::kNoReferrer)) {
    frame_request.SetNoReferrer();
    frame_request.SetNoOpener();
  }
  if (form->HasRel(HTMLFormElement::kNoOpener) ||
      (EqualIgnoringASCIICase(target_or_base_target, "_blank") &&
       !form->HasRel(HTMLFormElement::kOpener) &&
       form->GetDocument()
           .domWindow()
           ->GetFrame()
           ->GetSettings()
           ->GetTargetBlankImpliesNoOpenerEnabledWillBeRemoved())) {
    frame_request.SetNoOpener();
  }

  Frame* target_frame =
      form->GetDocument()
          .GetFrame()
          ->Tree()
          .FindOrCreateFrameForNavigation(frame_request, target_or_base_target)
          .frame;

  // Apply replacement now, before any async steps, as the result may change.
  WebFrameLoadType load_type = WebFrameLoadType::kStandard;
  LocalFrame* target_local_frame = DynamicTo<LocalFrame>(target_frame);
  if (target_local_frame &&
      target_local_frame->NavigationShouldReplaceCurrentHistoryEntry(
          frame_request, load_type)) {
    load_type = WebFrameLoadType::kReplaceCurrentItem;
  }

  return MakeGarbageCollected<FormSubmission>(
      copied_attributes.Method(), action_url, target_or_base_target,
      encoding_type, frame_request.GetSourceElement(), std::move(form_data),
      event, frame_request.GetNavigationPolicy(), triggering_event_info, reason,
      std::move(resource_request), target_frame, load_type,
      form->GetDocument().domWindow(),
      form->GetDocument().GetFrame()->GetLocalFrameToken(),
      CaptureSourceLocation(form->GetDocument().domWindow()),
      form->GetDocument()
          .domWindow()
          ->GetPolicyContainer()
          ->IssueKeepAliveHandle());
}


http://www.kler.cn/news/358778.html

相关文章:

  • Jmeter如何进行多服务器远程测试?
  • QT中中文显示乱码问题
  • flask-socketio-+Nginx反向代理在会议点名上的用作消息收发和提醒
  • asp.net Core 自定义中间件
  • 人工智能和机器学习之线性代数(二)
  • Java进阶——数据结构与算法之栈与递归小结(三)
  • 等保测评和等保认证有什么区别
  • Bayes-CNN-LSTM|基于贝叶斯优化的卷积-长短期神经网络多输入数据回归预测
  • 基于静态编译构建微服务应用
  • 【Docker】Docker (Dockerfile)的数据管理和网络通信
  • FPGA实现PCIE采集电脑端视频转SFP光口万兆UDP输出,基于XDMA+GTX架构,提供2套工程源码和技术支持
  • 51单片机的智能热水器控制系统【proteus仿真+程序+报告+原理图+演示视频】
  • 清空docker所有的数据
  • docker 初步理解
  • Axios 基本使用
  • 图书业务流程优化:Spring Boot进销存系统
  • 【排序】3.希尔排序法
  • 【论文速读】P-Tuning:GPT Understands, Too
  • hive_locks字段
  • 基于SpringBoot+Vue+uniapp的时间管理小程序的详细设计和实现(源码+lw+部署文档+讲解等)