首页 > 编程语言 >Chromium form表单post提交过程分析c++

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

时间:2024-10-17 22:22:51浏览次数:3  
标签:form Chromium frame request c++ attributes copied data

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());
}

标签:form,Chromium,frame,request,c++,attributes,copied,data
From: https://blog.csdn.net/jangdong/article/details/143029396

相关文章

  • C/C++语言基础--C++四大类型转换讲解
    本专栏目的更新C/C++的基础语法,包括C++的一些新特性前言通过前面几节课,我们学习了抽象、封装、继承、多态、异常等概念,这一篇我们将继续学习C++的类型转换,和C语言还有很大区别的;在本节课最后,也简要说了一下在计算机视角上看类型是什么样子的;C语言后面也会继续更新知识点,......
  • [转]Learn Power Platform Power Apps Dataverse Write a plug-in
    Learn PowerPlatform PowerApps Dataverse Writeaplug-inInthisarticleIPlugininterfacePluginBaseabstractclassServicesyoucanuseinyourcodePuttingitalltogetherShow2moreYoucancreate plug-ins byusingoneofthefollowingmetho......
  • vecode写c++遇到窗口一闪而过+中文乱码咋办
    本人没使用系统cmd窗口,而是使用了vscode内置终端,目的是为了之后输出中文的时候不乱码(vscode是utf-8,cmd是gbk,干脆全部使用vscode,不使用系统cmd作为输出窗口)附上配置文件:launch.json{//使用IntelliSense了解相关属性。//悬停以查看现有属性的描述。//欲了解......
  • c++ --类和对象(篇1)
    目录1.类的概念:2.类的定义3.对象的创建:4.封装5.继承1.类的概念:                类用于指定对象的形式,是一种用户自定义的数据类型,                它是一种封装了数据和函数的组合。类中的数据称为成员变量,函数称为成员函数。 ......
  • 【算法】C++中的二分查找
    ......
  • 牛客周赛63(C++实现)
    ......
  • Winform控件基础与进阶----DataGridView
    Winform控件基础之封装一个通用的DataGridView操作类1、创建Winform项目2、创建公共控件操作文件夹3、主界面1、控件布局2、提取通用方法3、静态方法类实现4、其他工具类实现1、JsonHelper工具类实现2、TxtOperateHelper工具类实现5、数据模型实现1、创建表结构模型2......
  • C++核心编程、面向对象
    目录一、内存分区模型1、运行程序前代码区全局区总结:2、运行程序后栈区堆区 3、new关键字基本使用开辟数组二、引用1、基本使用2、引用的注意事项3、引用做函数参数4、引用做函数返回值5、引用的本质6、常量引用三、函数提高1、函数的默认参数2、函数......
  • (新!)c++类与对象
    C++ 类&对象C++在C语言的基础上增加了面向对象编程,C++支持面向对象程序设计。类是C++的核心特性,通常被称为用户定义的类型。类用于指定对象的形式,是一种用户自定义的数据类型,它是一种封装了数据和函数的组合。类中的数据称为成员变量,函数称为成员函数。类可以被看作......
  • 【2024华为OD-E卷-100分-内存资源分配】(题目+思路+Java&C++&Python解析+在线测试)
    在线评测链接题目描述有一个简易内存池,内存按照大小粒度分类,每个粒度有若干个可用内存资源,用户会进行一系列内存申请,需要按需分配内存池中的资源返回申请结果成功失败列表。分配规则如下:分配的内存要大于等于内存的申请量,存在满足需求的内存就必须分配,优先分配粒度小的......