Files
nexus/sreweekly/articles/103/08-load-testing-webdav-servers.html
2026-09-12 17:23:01 +08:00

3157 lines
150 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="A tutorial on how to use the open source performance testing tool JMeter to perform load testing on the unique abilities you've coded into your WebDAV server.">
<meta name="keywords" content="WebDAV, requests, property, Load testing, Database, threading">
<meta property="og:description" content="A tutorial on how to use the open source performance testing tool JMeter to perform load testing on the unique abilities you've coded into your WebDAV server.">
<meta property="og:site_name" content="dzone.com">
<meta property="og:title" content="Load Testing WebDAV Servers">
<meta property="og:url" content="https://dzone.com/articles/load-testing-webdav-servers">
<meta property="og:image" content="https://dz2cdn1.dzone.com/storage/article-thumb/7625812-thumb.jpg">
<meta property="og:type" content="article">
<meta name="twitter:site" content="@DZoneInc">
<meta name="twitter:image" content="https://dz2cdn1.dzone.com/storage/article-thumb/7625812-thumb.jpg">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:description" content="A tutorial on how to use the open source performance testing tool JMeter to perform load testing on the unique abilities you've coded into your WebDAV server.">
<meta name="twitter:title" content="Load Testing WebDAV Servers">
<meta name="referrer" content="origin-when-cross-origin">
<meta name="google-site-verification" content="kndbhxcupfEqWmZclhCpB6vlgOs7QSmx2UHAGGnP2mA">
<meta name="df-verify" content="df0d76632b4543">
<link rel="icon" type="image/x-icon" href="https://dz2cdn1.dzone.com/themes/dz20/images/favicon.png">
<link rel="image_src" href="https://dz2cdn1.dzone.com/storage/article-thumb/7625812-thumb.jpg">
<link rel="canonical" href="https://dzone.com/articles/load-testing-webdav-servers">
<title>Load Testing WebDAV Servers</title>
<link rel="preload" href="https://dz2cdn1.dzone.com/themes/dz20/font/fontello.woff?11773374" as="font" type="font/woff" crossorigin="anonymous">
<link rel="stylesheet" media="all" href="https://dz2cdn1.dzone.com/themes/dz20/ftl/icons.css">
<link rel="stylesheet" media="all" href="https://dz2cdn1.dzone.com/themes/dz20/lib/static/bootstrap/bootstrap.min.css">
<link rel="stylesheet" media="all" href="https://dz2cdn1.dzone.com/themes/dz20/ftl/article/global.css">
<link rel="stylesheet" media="all" href="https://dz2cdn1.dzone.com/themes/dz20/ftl/header-updated/styles.css">
<style>
:root {
--xs-size: 2px;
--sm-size: 5px;
--md-size: 10px;
--lg-size: 15px;
--xl-size: 25px;
--sm-border-size: 8px;
--sm-font-size: 13px;
--sm-plus-font-size: 16px;
--md-font-size: 18px;
--lg-font-size: 22px;
--xl-font-size: 26px;
}
/* Display Quick-Access Classes */
.display-none { display: none; }
.display-block { display: block; }
.display-inline { display: inline; }
.display-inline-block { display: inline-block; }
/* Margin Quick-Access Classes */
.m-xs { margin: var(--xs-size); }
.m-sm { margin: var(--sm-size); }
.m-md { margin: var(--md-size); }
.m-lg { margin: var(--lg-size); }
.m-xl { margin: var(--xl-size); }
.mt-xs, .my-xs { margin-top: var(--xs-size); }
.mr-xs, .mx-xs { margin-right: var(--xs-size); }
.mb-xs, .my-xs { margin-bottom: var(--xs-size); }
.ml-xs, .mx-xs { margin-left: var(--xs-size); }
.mt-sm, .my-sm { margin-top: var(--sm-size); }
.mr-sm, .mx-sm { margin-right: var(--sm-size); }
.mb-sm, .my-sm { margin-bottom: var(--sm-size); }
.ml-sm, .mx-sm { margin-left: var(--sm-size); }
.mt-md, .my-md { margin-top: var(--md-size); }
.mr-md, .mx-md { margin-right: var(--md-size); }
.mb-md, .my-md { margin-bottom: var(--md-size); }
.ml-md, .mx-md { margin-left: var(--md-size); }
.mt-lg, .my-lg { margin-top: var(--lg-size); }
.mr-lg, .mx-lg { margin-right: var(--lg-size); }
.mb-lg, .my-lg { margin-bottom: var(--lg-size); }
.ml-lg, .mx-lg { margin-left: var(--lg-size); }
.mt-xl, .my-xl { margin-top: var(--xl-size); }
.mr-xl, .mx-xl { margin-right: var(--xl-size); }
.mb-xl, .my-xl { margin-bottom: var(--xl-size); }
.ml-xl, .mx-xl { margin-left: var(--xl-size); }
.ml-auto, .mx-auto { margin-left: auto; }
.mr-auto, .mx-auto { margin-right: auto; }
.mt-auto, .my-auto { margin-top: auto; }
.mb-auto, .my-auto { margin-bottom: auto; }
.my-none, .mt-none { margin-top: 0 !important; }
.mx-none, .mr-none { margin-right: 0 !important; }
.my-none, .mb-none { margin-bottom: 0 !important; }
.mx-none, .ml-none { margin-left: 0 !important; }
/* Padding Quick-Access Classes */
.p-xs { padding: var(--xs-size); }
.p-sm { padding: var(--sm-size); }
.p-md { padding: var(--md-size); }
.p-lg { padding: var(--lg-size); }
.p-xl { padding: var(--xl-size); }
.pt-xs, .py-xs { padding-top: var(--xs-size); }
.pr-xs, .px-xs { padding-right: var(--xs-size); }
.pb-xs, .py-xs { padding-bottom: var(--xs-size); }
.pl-xs, .px-xs { padding-left: var(--xs-size); }
.pt-sm, .py-sm { padding-top: var(--sm-size); }
.pr-sm, .px-sm { padding-right: var(--sm-size); }
.pb-sm, .py-sm { padding-bottom: var(--sm-size); }
.pl-sm, .px-sm { padding-left: var(--sm-size); }
.pt-md, .py-md { padding-top: var(--md-size); }
.pr-md, .px-md { padding-right: var(--md-size); }
.pb-md, .py-md { padding-bottom: var(--md-size); }
.pl-md, .px-md { padding-left: var(--md-size); }
.pt-lg, .py-lg { padding-top: var(--lg-size); }
.pr-lg, .px-lg { padding-right: var(--lg-size); }
.pb-lg, .py-lg { padding-bottom: var(--lg-size); }
.pl-lg, .px-lg { padding-left: var(--lg-size); }
.pt-xl, .py-xl { padding-top: var(--xl-size); }
.pr-xl, .px-xl { padding-right: var(--xl-size); }
.pb-xl, .py-xl { padding-bottom: var(--xl-size); }
.pl-xl, .px-xl { padding-left: var(--xl-size); }
.py-none, .pt-none { padding-top: 0 !important; }
.px-none, .pr-none { padding-right: 0 !important; }
.py-none, .pb-none { padding-bottom: 0 !important; }
.px-none, .pl-none { padding-left: 0 !important; }
/* Flex Quick-Access Classes */
.flex {
display: flex;
}
.flex-column {
display: flex;
flex-direction: column;
}
.flex-column-reverse {
display: flex;
flex-direction: column-reverse;
}
.flex-row {
display: flex;
flex-direction: row;
}
.flex-row-reverse {
display: flex;
flex-direction: row-reverse;
}
.flex-wrap {
flex-wrap: wrap;
}
.flex-grow {
flex-grow: 1;
}
.align-center { align-items: center; }
.align-end { align-items: flex-end; }
.content-center {
align-content: center;
}
.justify-center { justify-content: center; }
.justify-start { justify-content: flex-start; }
.justify-end { justify-content: flex-end; }
.justify-around { justify-content: space-around; }
.justify-between { justify-content: space-between; }
.justify-evenly { justify-content: space-evenly; }
.gap-sm { gap: var(--sm-size); }
.gap-md { gap: var(--md-size); }
.gap-lg { gap: var(--lg-size); }
.gap-xl { gap: var(--xl-size); }
/* Display Quick-Access Classes */
.inline-block { display: inline-block; }
/* Font Quick-Access Classes */
.font-xl { font-size: var(--xl-font-size); }
.font-lg { font-size: var(--lg-font-size); }
.font-md { font-size: var(--md-font-size); }
.font-sm-plus { font-size: var(--sm-plus-font-size); }
.font-sm { font-size: var(--sm-font-size); }
.font-strike { text-decoration: line-through; }
.font-underline { text-decoration: underline; }
.font-overline { text-decoration: overline; }
.font-italic { font-style: italic; }
.font-bold { font-weight: bold; }
.font-black { color: #000000; }
.font-white { color: #ffffff; }
.font-gray { color: var(--brand-gray-text); }
.font-danger { color: var(--header-dropdown-button-bg-danger); }
.font-center { text-align: center; }
.no-wrap { white-space: nowrap; }
/* Consistent headings between h and non-h tags */
.heading {
margin-top: 0;
margin-bottom: var(--md-size);
}
.heading.font-xl { line-height: var(--xl-font-size); }
.heading.font-lg { line-height: var(--lg-font-size); }
.heading.font-md { line-height: var(--md-font-size); }
.heading.font-sm-plus { line-height: var(--sm-plus-font-size); }
.heading.font-sm { line-height: var(--sm-font-size); }
/* Font Clamp Quick-Access Classes */
.line-clamp,
.line-clamp-2,
.line-clamp-3,
.line-clamp-4,
.line-clamp-5 {
display: -webkit-box;
-webkit-line-clamp: 4;
-webkit-box-orient: vertical;
overflow: hidden;
text-overflow: ellipsis;
}
.line-clamp-2 { -webkit-line-clamp: 2 !important; }
.line-clamp-3 { -webkit-line-clamp: 3 !important; }
.line-clamp-4 { -webkit-line-clamp: 4 !important; }
.line-clamp-5 { -webkit-line-clamp: 5 !important; }
/* User-Select Quick-Access Classes */
.select-none { user-select: none; }
/* Position Quick-Access Classes */
.absolute { position: absolute; }
.relative { position: relative; }
.float-left { float: left; }
.float-right { float: right; }
.pos-top { top: 0; }
.pos-right { right: 0; }
.pos-bottom { bottom: 0; }
.pos-left { left: 0; }
.va-top { vertical-align: top; }
.va-middle { vertical-align: middle; }
.va-bottom { vertical-align: bottom; }
/* Transition Quick-Access Classes */
.trans-linear-quick {
transition: all 0.15s linear;
}
/* Background Quick-Access Classes */
.bg-gray { background: #cccccc; }
.bg-white { background-color: white; }
.bg-none { background: none; }
/* Border Quick-Access Classes */
.border-gray { border: 1px solid #cccccc; }
.tab-pane.border-gray { border: 1px solid #ddd; }
.no-border, .border-none { border: none !important; }
.bt-none { border-top: none !important; }
.br-none { border-right: none !important; }
.bb-none { border-bottom: none !important; }
.bl-none { border-left: none !important; }
/* Border Radius Quick-Access Classes */
.round-t-sm, .round-tl-sm { border-top-left-radius: var(--sm-border-size); }
.round-t-sm, .round-tr-sm { border-top-right-radius: var(--sm-border-size); }
.round-b-sm, .round-bl-sm { border-bottom-left-radius: var(--sm-border-size); }
.round-b-sm, .round-br-sm { border-bottom-right-radius: var(--sm-border-size); }
.round-sm { border-radius: var(--sm-border-size); }
.round-fully { border-radius: 50%; }
/* Misc Quick-Access Classes */
.haikei {
position: relative;
background-image: url('https://dz2cdn1.dzone.com/themes/dz20/images/polygon-scatter-haikei-shapes.svg');
background-repeat: no-repeat;
background-size: cover;
}
.haikei:before {
content: '';
position:absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: var(--color-event-background);
z-index: -1;
}
.margin-auto-center {
display: block;
margin-left: auto;
margin-right: auto;
}
.flex-auto-center {
display: flex;
margin-left: auto;
margin-right: auto;
}
.mw-1100 { max-width: 1100px; }
.mw-1300 { max-width: 1300px; }
.full-width { width: 100%; }
.h-separator {
background-color: #cccccc;
height: 1px;
width: 100%;
margin: 5px auto;
}
.no-spacing {
margin: 0 !important;
padding: 0 !important;
}
.inherit-color { color: inherit; }
.inherit-decoration { text-decoration: inherit; }
/* Table Quick-Access Classes */
.table-border-gray tr:not(:last-child) {
border-bottom: 1px solid #cccccc;
}
table.full-width tr td:last-child {
width:100%;
}
/* Animation Quick-Access Classes */
@keyframes anim-spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(359deg); }
}
.anim-spin {
display: inline-block;
animation: anim-spin 2s infinite linear;
}
.hov-pointer { cursor: pointer; }
.hov-brighten:hover { filter: brightness(1.2); }
.hov-darken:hover { filter: brightness(0.95); }
.hov-underline:hover { text-decoration: underline; }
/* Small tweaks related to components when using these styles */
.nav-tabs {
border-bottom: none;
}
.tab-content > .flex-column.active,
.tab-content > .flex-row.active {
display: flex;
}
/* Alpine components with x-cloak should not be visible by default until conditionals kick in */
[x-cloak] { display: none !important; }
</style>
<link rel="stylesheet" media="all" href="https://dz2cdn1.dzone.com/themes/dz20/ftl/alpine-components/modal.css">
<script defer src="https://dz2cdn1.dzone.com/themes/dz20/lib/alpinejs/3.13.2/cdn.min.js"></script>
<script>
document.addEventListener('alpine:init', () => {
Alpine.store('article', {
id: null,
engagement: {
open: false,
page: 1,
users: [],
additional: true,
loading: false,
initializing: false,
unauthorized: false,
enqueued: null,
dequeued: null,
reset() {
this.open = false;
this.page = 1;
this.users.splice(0);
this.additional = true;
this.loading = false;
this.initializing = false;
this.enqueued = null;
this.dequeued = null;
},
enqueue(user) {
this.dequeued = null;
this.enqueued = user;
},
dequeue(user) {
this.enqueued = null;
this.dequeued = user;
},
add(user) {
this.users.push(user);
this.enqueued = null;
},
remove(user) {
const index = this.users.findIndex(u => u.id === user.id);
if (index !== -1) {
this.users.splice(index, 1);
}
this.dequeued = null;
},
contains(user) {
return this.users.filter(u => u.id === user.id).length;
}
}
});
Alpine.effect(() => {
const store = Alpine.store('article');
if (!store.engagement.additional && store.engagement.enqueued) {
if (!store.engagement.contains(store.engagement.enqueued)) {
store.engagement.add(store.engagement.enqueued);
}
}
});
Alpine.effect(() => {
const store = Alpine.store('article');
if (store.engagement.page && store.engagement.dequeued) {
store.engagement.remove(store.engagement.dequeued);
}
})
});
</script></head>
<body x-data>
<div class="skybox skybox-closeBtn dz_skybox" data-gpt-slot="skybox" id="div-gpt-ad-1435246566686-99"></div>
<header id="ftl-header">
<div class="header-top">
<div class="header-container">
<div class="pull-left logo-container">
<div class="logo">
<a class="inner" href="/">
<picture>
<source srcset="https://dz2cdn1.dzone.com/themes/dz20/images/dz_logo_2021_cropped.webp" type="image/webp">
<source srcset="https://dz2cdn1.dzone.com/themes/dz20/images/dz_logo_2021_cropped.png" type="image/png">
<img src="https://dz2cdn1.dzone.com/themes/dz20/images/dz_logo_2021_cropped.png" width="181" height="56" alt="DZone">
</picture>
</a>
</div>
</div>
<div class="pull-right login-and-search">
<div id="authenticated-block" class="logged-in">
<div class="welcome-back">Thanks for visiting DZone today,</div>
<div id="user-header" class="user-info">
<button class="user-avatar">
<span id="header-username" class="username"></span>
<img id="header-avatar" src="" alt="user avatar">
</button>
<div id="user-dropdown" class="browse-user-menu">
<div class="user-content">
<a id="header-user-plug" href="#" class="user-description"></a>
<a id="header-user-edit" href="#" class="edit-profile">Edit Profile</a>
</div>
<ul class="user-actions">
<li id="first-user-action">
<a id="header-dropdown-manage-email" href="#">Manage Email Subscriptions</a>
</li>
<li>
<a href="/articles/how-to-submit-a-post-to-dzone?utm_source=DZone&utm_medium=user_dropdown&utm_campaign=how_to_post">
How to Post to DZone
</a>
</li>
<li>
<a href="/articles/dzones-article-submission-guidelines">
Article Submission Guidelines
</a>
</li>
</ul>
<div class="bottom">
<a href="/users/logout.html" class="sign-out">Sign Out</a>
<a id="dropdown-view-profile" href="#" class="view-profile">View Profile</a>
</div>
</div>
</div>
<div class="post-content">
<button id="post-button" class="post-content--button">
<span class="post-class">Post</span>
<i class="icon-plus"></i>
</button>
<div id="post-menu" class="posting-links">
<div class="posting-links-menu">
<ul>
<li>
<img src="https://dz2cdn1.dzone.com/themes/dz20/images/dz-postarticle.svg" width="15" height="18" style="width: 15px; height: 18px;">
<a href="/content/article/post.html">Post an Article</a>
</li>
<li>
<a id="drafts-link" href="#">Manage My Drafts</a>
</li>
</ul>
</div>
</div>
</div>
</div>
<div id="unauthenticated-block">
<div class="dz-intro">Over 2 million developers have joined DZone.</div>
<div class="mobile-invisible sign-in-join">
<a href="/users/login.html">Log In</a>
<span class="dz-intro-span">/</span>
<a href="/static/registration.html">Join</a>
</div>
<a class="join-icon" href="/users/login.html" aria-label="User">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide svg-user lucide-user-icon lucide-user">
<path d="M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2"></path>
<circle cx="12" cy="7" r="4"></circle>
</svg>
</a>
</div>
<script>
document.addEventListener('alpine:init', () => {
Alpine.data('searchDrawer', () => ({
open: false,
query: '',
minCharsMet: false,
toggleVisibility() {
this.open = !this.open;
if (this.open) {
this.$nextTick(() => {
this.$refs.query.focus();
});
}
},
updateSearchValue() {
if (!this.query || !this.query.length || this.query.length < 3) {
this.minCharsMet = false;
return;
}
this.minCharsMet = true;
localStorage.setItem('ls.searchValue', this.query);
},
searchSite() {
if (this.minCharsMet) {
window.location = '/search';
}
}
}));
});
</script>
<div class="headerSearch" x-data="searchDrawer()" x-cloak>
<button class="btn-search dropdown-toggle" x-on:click="toggleVisibility()" aria-label="Search">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide svg-search lucide-search-icon lucide-search">
<path d="m21 21-4.34-4.34"></path>
<circle cx="11" cy="11" r="8"></circle>
</svg>
</button>
<template x-teleport=".header-container">
<div id="search-drawer" x-show="open" x-on:click.outside="open = false" x-transition>
<div class="search-input">
<input type="text"
placeholder="Search"
autofocus="autofocus"
x-model="query"
x-ref="query"
x-on:input.change="updateSearchValue()"
x-on:keyup.enter="searchSite()"
>
<button x-on:click="searchSite()" x-bind:disabled="!minCharsMet">
<span>Search</span>
</button>
</div>
<div class="search-footer">
Please enter at least three characters to search
</div>
</div>
</template>
</div>
</div>
</div> </div>
<div class="header-bottom">
<div class="header-bottom-container">
<a class="resource-link" href="/refcardz">Refcards</a>
<a class="resource-link" href="/trendreports">Trend Reports</a>
<div class="resource-link link-menu">
<a href="/events">Events</a>
<a href="/events/video-library">Video Library</a>
</div>
</div>
</div>
<nav class="header-menu-bar">
<div class="header-menu resource-category">
<a href="/refcardz">Refcards</a>
</div>
<div class="header-menu-separator resource-category-separator"></div>
<div class="header-menu resource-category">
<a href="/trendreports">Trend Reports</a>
</div>
<div class="header-menu-separator resource-category-separator"></div>
<div class="header-menu resource-category no-bottom-radius" data-click-activation>
<p class="menu-label">Events</p>
<div class="header-menu-items">
<div class="header-menu-columns">
<a class="header-menu-item" href="/events">View Events</a>
<a class="header-menu-item" href="/events/video-library">Video Library</a>
</div>
</div>
</div>
<div class="header-menu zone-menu" data-click-activation>
<p class="menu-label">Zones <i class="icon-down-dir icon-closed"></i><i class="icon-right-dir icon-open"></i></p>
<div class="header-menu-items">
<div class="header-menu-columns">
<div class="header-menu-column-item">
<a class="header-menu-item" href="/culture-and-methodologies">Culture and Methodologies</a>
<a class="header-menu-item" href="/agile">Agile</a>
<a class="header-menu-item" href="/career-development">Career Development</a>
<a class="header-menu-item" href="/methodologies">Methodologies</a>
<a class="header-menu-item" href="/team-management">Team Management</a>
</div>
<div class="header-menu-column-item">
<a class="header-menu-item" href="/data-engineering">Data Engineering</a>
<a class="header-menu-item" href="/ai-ml">AI/ML</a>
<a class="header-menu-item" href="/big-data">Big Data</a>
<a class="header-menu-item" href="/data">Data</a>
<a class="header-menu-item" href="/databases">Databases</a>
<a class="header-menu-item" href="/iot">IoT</a>
</div>
<div class="header-menu-column-item">
<a class="header-menu-item" href="/software-design-and-architecture">Software Design and Architecture</a>
<a class="header-menu-item" href="/cloud-architecture">Cloud Architecture</a>
<a class="header-menu-item" href="/containers">Containers</a>
<a class="header-menu-item" href="/integration">Integration</a>
<a class="header-menu-item" href="/microservices">Microservices</a>
<a class="header-menu-item" href="/performance">Performance</a>
<a class="header-menu-item" href="/security">Security</a>
</div>
<div class="header-menu-column-item">
<a class="header-menu-item" href="/coding">Coding</a>
<a class="header-menu-item" href="/frameworks">Frameworks</a>
<a class="header-menu-item" href="/java">Java</a>
<a class="header-menu-item" href="/javascript">JavaScript</a>
<a class="header-menu-item" href="/languages">Languages</a>
<a class="header-menu-item" href="/tools">Tools</a>
</div>
<div class="header-menu-column-item">
<a class="header-menu-item" href="/testing-deployment-and-maintenance">Testing, Deployment, and Maintenance</a>
<a class="header-menu-item" href="/deployment">Deployment</a>
<a class="header-menu-item" href="/devops-and-cicd">DevOps and CI/CD</a>
<a class="header-menu-item" href="/maintenance">Maintenance</a>
<a class="header-menu-item" href="/monitoring-and-observability">Monitoring and Observability</a>
<a class="header-menu-item" href="/testing-tools-and-frameworks">Testing, Tools, and Frameworks</a>
</div>
<div class="header-menu-column-item sponsored">
<a class="header-menu-item" href="javascript:void(0)">Partner Zones</a>
<a class="header-menu-item" href="/hubs/build-ai-agents-that-are-ready-for-production/">Build AI Agents That Are Ready for Production</a>
</div>
</div>
</div>
</div>
<div class="header-menu parent-category" tabindex="1">
<a href="/culture-and-methodologies">Culture and Methodologies</a>
<div class="header-menu-items">
<a class="header-menu-item" href="/agile">Agile</a>
<a class="header-menu-item" href="/career-development">Career Development</a>
<a class="header-menu-item" href="/methodologies">Methodologies</a>
<a class="header-menu-item" href="/team-management">Team Management</a>
</div>
</div>
<div class="header-menu-separator parent-category-separator"></div>
<div class="header-menu parent-category" tabindex="2">
<a href="/data-engineering">Data Engineering</a>
<div class="header-menu-items">
<a class="header-menu-item" href="/ai-ml">AI/ML</a>
<a class="header-menu-item" href="/big-data">Big Data</a>
<a class="header-menu-item" href="/data">Data</a>
<a class="header-menu-item" href="/databases">Databases</a>
<a class="header-menu-item" href="/iot">IoT</a>
</div>
</div>
<div class="header-menu-separator parent-category-separator"></div>
<div class="header-menu parent-category" tabindex="3">
<a href="/software-design-and-architecture">Software Design and Architecture</a>
<div class="header-menu-items">
<a class="header-menu-item" href="/cloud-architecture">Cloud Architecture</a>
<a class="header-menu-item" href="/containers">Containers</a>
<a class="header-menu-item" href="/integration">Integration</a>
<a class="header-menu-item" href="/microservices">Microservices</a>
<a class="header-menu-item" href="/performance">Performance</a>
<a class="header-menu-item" href="/security">Security</a>
</div>
</div>
<div class="header-menu-separator parent-category-separator"></div>
<div class="header-menu parent-category" tabindex="4">
<a href="/coding">Coding</a>
<div class="header-menu-items">
<a class="header-menu-item" href="/frameworks">Frameworks</a>
<a class="header-menu-item" href="/java">Java</a>
<a class="header-menu-item" href="/javascript">JavaScript</a>
<a class="header-menu-item" href="/languages">Languages</a>
<a class="header-menu-item" href="/tools">Tools</a>
</div>
</div>
<div class="header-menu-separator parent-category-separator"></div>
<div class="header-menu parent-category" tabindex="5">
<a href="/testing-deployment-and-maintenance">Testing, Deployment, and Maintenance</a>
<div class="header-menu-items">
<a class="header-menu-item" href="/deployment">Deployment</a>
<a class="header-menu-item" href="/devops-and-cicd">DevOps and CI/CD</a>
<a class="header-menu-item" href="/maintenance">Maintenance</a>
<a class="header-menu-item" href="/monitoring-and-observability">Monitoring and Observability</a>
<a class="header-menu-item" href="/testing-tools-and-frameworks">Testing, Tools, and Frameworks</a>
</div>
</div>
<div class="header-menu-separator parent-category-separator"></div>
<div class="header-menu parent-category sponsored" tabindex="6">
<a href="javascript:void(0)">Partner Zones</a>
<div class="header-menu-items sponsored">
<a class="header-menu-item" href="/hubs/build-ai-agents-that-are-ready-for-production/">Build AI Agents That Are Ready for Production</a>
</div>
</div>
<div class="header-menu-separator parent-category-separator"></div>
</nav>
</header>
<script>
const csrf = {
parameter: 'TH_CSRF',
header: 'X-TH-CSRF',
token: '-5862638139309433156'
}; // set csrf for auth-status script
</script>
<script>
addEventListener('DOMContentLoaded', function() {
handleRedirects();
handleMenus();
handleMobileMenuHeights();
handleGotoLinks();
});
function isHidden(element) {
try {
return window.getComputedStyle(element).display === 'none';
} catch (_) {
return false;
}
}
function getLink(element) {
if (element.hasAttribute('data-goto')) {
return element.getAttribute('data-goto');
}
return element.href;
}
function isLeftClick(event) {
if (event.altKey || event.shiftKey) {
return false;
} else if ('buttons' in event || 'which' in event) {
return event.buttons === 1 || event.which === 1;
} else {
return (event.button === 1 || (event.type === 'click'));
}
}
function handleRedirects() {
const redirections = [...document.querySelectorAll('[data-activate-menu]'), ...document.querySelectorAll('[data-click-target]')];
redirections.forEach(function(element) {
const menuSelector = element.getAttribute('data-activate-menu') || element.getAttribute('data-click-target');
const redirectingElement = document.querySelector(menuSelector);
if (redirectingElement) {
element.style.cursor = 'pointer';
const redirect = function(e) {
if (redirectingElement.hasAttribute('href') || redirectingElement.hasAttribute('data-goto')) {
if (redirectingElement.hasAttribute('data-new-window') || e.ctrlKey || e.metaKey) {
window.open(getLink(redirectingElement), '_blank');
} else {
window.open(getLink(redirectingElement), '_self');
}
} else {
const evt = new e.constructor(e.type, e);
redirectingElement.dispatchEvent(evt);
}
};
element.addEventListener('mouseup', redirect);
element.addEventListener('mousedown', (e) => e.preventDefault());
element.addEventListener('click', (e) => e.preventDefault());
}
});
}
function handleMenus() {
const menuElements = [
...document.querySelectorAll('.header-menu > a'),
...document.querySelectorAll('.header-menu > p.menu-label')
];
let scrollYMemory = -1;
function scrollToMemory() {
if (scrollYMemory !== -1) {
setTimeout(function() {
window.scrollTo(0, scrollYMemory);
scrollYMemory = -1;
}, 10);
}
}
function hideMenus() {
// unfocus menus & items, and set the menus to non-visible.
menuElements.forEach(function (element) {
element.blur();
element.parentElement.blur();
element.parentElement.classList.remove('menu-opened');
const menuItems = element.parentElement.querySelector('.header-menu-items');
if (menuItems) {
menuItems.style.display = 'none';
}
});
const wasHidden = document.body.style.overflowY === 'hidden';
document.body.style.overflowY = 'auto';
if (wasHidden) {
scrollToMemory();
}
}
function isEventOutsideMenu(e) {
return e.target.closest && !e.target.closest('.header-menu') && !e.target.closest('[data-activate-menu]');
}
// Handle mobile menu toggling
menuElements.forEach(function(element) {
const menu = element.parentElement;
const headerItems = menu.querySelector('.header-menu-items');
const menuEntries = headerItems ? headerItems.querySelectorAll('.header-menu-item') : [];
const focus = function() {
menu.focus();
menu.classList.add('menu-opened');
if (headerItems) {
headerItems.style.display = 'block';
}
if (menu.classList.contains('zone-menu')) {
scrollYMemory = window.scrollY;
document.body.style.overflowY = 'hidden';
} else {
scrollYMemory = -1;
}
};
const unfocus = function() {
menu.blur();
menu.classList.remove('menu-opened');
if (headerItems) {
headerItems.style.display = 'none';
}
const wasHidden = document.body.style.overflowY === 'hidden';
document.body.style.overflowY = 'auto';
if (wasHidden) {
scrollToMemory();
}
};
const toggleMenuVisibility = function(e) {
if ((e.type === 'click' || e.type === 'mouseup') && !isLeftClick(e)) {
e.preventDefault();
return;
}
const hidden = isHidden(headerItems);
if (menu.hasAttribute('data-click-activation')) { // handle click activated toggling
if (hidden) {
hideMenus(); // hide other open menus first
focus();
} else {
unfocus();
}
e.preventDefault();
} else if (hidden) {
hideMenus(); // hide other open menus first
focus();
e.preventDefault(); // prevent 'click' event from firing when menu is hidden
}
};
element.addEventListener('touchend', toggleMenuVisibility);
element.addEventListener('mouseup', toggleMenuVisibility);
// Add hover events to non-click-activated menus, even though CSS should cover it.
if (!menu.hasAttribute('data-click-activation')) {
menu.addEventListener('mouseover', function () {
hideMenus(); // hide other open menus first
focus();
});
menu.addEventListener('mouseout', function (e) {
if (isEventOutsideMenu(e)) {
unfocus();
}
});
}
// Hide menu when child is clicked
menuEntries.forEach(function(menuEntry) {
const linkToItem = function(e) {
if (e.type === 'mousedown' || e.type === 'click') {
e.preventDefault();
return;
}
if (e.type === 'mouseup' && !isLeftClick(e)) {
e.preventDefault();
return;
}
window.open(getLink(menuEntry), (e.ctrlKey || e.metaKey) ? '_blank' : (menuEntry.target || '_self'));
unfocus();
e.preventDefault();
};
const linkToMobileItem = function(e) {
if (e.type === 'touchstart') {
menuEntry.setAttribute('data-touchmove', false);
} else if (e.type === 'touchmove') {
menuEntry.setAttribute('data-touchmove', true);
} else if (e.type === 'touchend' && (!menuEntry.hasAttribute('data-touchmove') || menuEntry.getAttribute('data-touchmove').toLowerCase() === 'false')) {
window.open(getLink(menuEntry), (e.ctrlKey || e.metaKey) ? '_blank' : (menuEntry.target || '_self'));
unfocus();
e.preventDefault();
}
};
menuEntry.addEventListener('mousedown', linkToItem);
menuEntry.addEventListener('mouseup', linkToItem);
menuEntry.addEventListener('click', linkToItem);
menuEntry.addEventListener('touchstart', linkToMobileItem);
menuEntry.addEventListener('touchmove', linkToMobileItem);
menuEntry.addEventListener('touchend', linkToMobileItem);
});
});
function hideIfNonMenuBounds(e) {
if (isEventOutsideMenu(e)) {
hideMenus();
}
}
addEventListener('mousemove', hideIfNonMenuBounds);
addEventListener('touchend', hideIfNonMenuBounds);
addEventListener('mouseup', hideIfNonMenuBounds);
addEventListener('mousedown', hideIfNonMenuBounds);
addEventListener('click', hideIfNonMenuBounds);
}
function handleMobileMenuHeights() {
function setAppHeight() {
document.documentElement.style.setProperty('--app-height', window.innerHeight + 'px');
}
addEventListener('resize', function() {
setAppHeight();
});
setAppHeight();
}
function handleGotoLinks() {
// Add anchor mimicking to elements with data-goto attributes
// This addresses SEO concerns of linking to noindex pages by allowing JS to handle the URL
const anchorElements = document.querySelectorAll('*[data-goto]');
anchorElements.forEach((anchorElement) => {
anchorElement.addEventListener('mouseover', () => {
anchorElement.style.cursor = 'pointer';
anchorElement.style.textDecoration = 'underline';
});
anchorElement.addEventListener('mouseout', () => {
anchorElement.style.cursor = 'unset';
anchorElement.style.textDecoration = 'unset';
});
anchorElement.addEventListener('mouseup', (e) => {
e.preventDefault();
});
anchorElement.addEventListener('mousedown', (e) => {
e.preventDefault();
});
anchorElement.addEventListener('click', (e) => {
e.preventDefault();
const anchorHref = anchorElement.getAttribute('data-goto');
if (anchorElement.hasAttribute('data-new-window') || e.ctrlKey || e.metaKey) {
window.open(anchorHref, '_blank');
} else {
window.open(anchorHref, '_self');
}
});
});
}
</script><script>
const authenticatedBlock = document.querySelector('#authenticated-block');
const unauthenticatedBlock = document.querySelector('#unauthenticated-block');
let authenticated = {
isAuthenticated: false,
isAdmin: false,
user: {
id: null,
name: null,
url: null,
profileImage: null,
}
};
fetch('/services/internal/data/articles-getAuthenticationStatus', {
headers: {
'Accept': 'application/json'
}
})
.then(function (result) {
return result.json()
})
.then(function (result) {
const res = result.result.data
if (!res.authenticated) {
unauthenticatedBlock.classList.add('shown')
} else {
authenticated.user.id = res.id;
authenticated.user.name = res.realName;
authenticated.user.url = res.profileUrl;
authenticated.user.profileImage = res.avatar;
authenticated.user.jobTitle = res.jobTitle;
authenticated.user.companyName = res.companyName;
bindProps('#header-username', null, null, (res.firstName || res.username), null)
bindProps('#header-avatar', null, res.avatar, null, null)
bindProps('#header-user-plug', res.profileUrl, null, res.realName, null)
bindProps('#header-user-edit', '/users/' + res.id + '/edit.html', null, null, null)
bindProps('#header-dropdown-manage-email', '/newsletters/' + res.id + '/manage.html', null, null, null)
bindProps('#dropdown-view-profile', res.profileUrl, null, null, null)
bindProps('#drafts-link', '/users/' + res.id + '/drafts.html', null, null, null)
if (res.isAdmin) {
// Construct backwards so the #after call places elements in the correct order
const firstUserAction = document.querySelector('#first-user-action')
const adminConsoleItem = document.createElement('li')
const adminConsoleLink = createLink('/dzone/staff/index.html', 'Admin Console')
adminConsoleItem.appendChild(adminConsoleLink)
firstUserAction.after(adminConsoleItem)
const moderationItem = document.createElement('li')
const moderationLink = createLink('/moderation/list.html', 'Moderation')
moderationItem.appendChild(moderationLink)
firstUserAction.after(moderationItem)
const bountyModerationItem = document.createElement('li')
const bountyModerationLink = createLink('/moderation/bounties', 'Bounty Moderation')
bountyModerationItem.appendChild(bountyModerationLink)
firstUserAction.after(bountyModerationItem)
}
authenticated.isAuthenticated = res.authenticated;
authenticated.isAdmin = res.isAdmin;
authenticatedBlock.classList.add('shown')
}
}).catch(function (result) {
console.error(result)
})
/**
* Binds different properties to the selected element.
*
* @param selector - Selector to select the element
* @param href - href attribute value
* @param src - src attribute value
* @param innerHTML - innerHTML property value
* @param innerText - innerText property value
*/
function bindProps(selector, href, src, innerHTML, innerText) {
const element = document.querySelector(selector)
if (element) {
if (href) element.href = href
if (src) element.src = src
if (innerHTML) element.innerHTML = innerHTML
if (innerText) element.innerText = innerText
}
}
/**
* Creates a new link element.
*
* @param href - href attribute value
* @param innerText - innerText property value
* @returns {HTMLAnchorElement} The generated link element
*/
function createLink(href, innerText) {
const link = document.createElement('a')
link.href = href
link.innerText = innerText
return link
}
</script><script>
const userHeader = document.querySelector('#user-header')
const userDropdown = document.querySelector('#user-dropdown')
const postDropdown = document.querySelector('#post-button')
const postMenu = document.querySelector('#post-menu')
let userDropdownOpen = false
let postDropdownOpen = false
document.addEventListener('click', function(event) {
if (postDropdown && postDropdown.contains(event.target)) {
setUserDropdown(false)
setPostDropdown(!postDropdownOpen)
} else if (userHeader && userHeader.contains(event.target)) {
setPostDropdown(false)
setUserDropdown(!userDropdownOpen)
} else {
setUserDropdown(false)
setPostDropdown(false)
}
})
function setUserDropdown(value) {
userDropdownOpen = value
if (userDropdownOpen) {
if (userDropdown) {
userDropdown.classList.add('open')
}
} else {
if (userDropdown) {
userDropdown.classList.remove('open')
}
}
}
function setPostDropdown(value) {
postDropdownOpen = value
if (postDropdownOpen) {
if (postMenu) {
postMenu.classList.add('open')
}
} else {
if (postMenu) {
postMenu.classList.remove('open')
}
}
}
</script><script>
document.addEventListener("alpine:init", () => {
Alpine.store('global', {
executeHttp(path, body, method) {
const options = {
method: method,
headers: {
[csrf.header]: csrf.token
}
};
if (method !== 'GET') {
options.body = JSON.stringify(body);
options.headers = {
...options.headers,
'Content-Type': 'application/json; charset=UTF-8'
};
}
return new Promise((resolve, reject) => {
fetch(path, options)
.then(res => {
if (!res.ok) {
reject(res);
} else {
resolve(res);
}
})
.catch(err => reject(err));
});
},
getFromService(path) {
return this.executeHttp(path, null, 'GET');
},
postToService(path, body = {}) {
return this.executeHttp(path, body, 'POST');
},
putToService(path, body = {}) {
return this.executeHttp(path, body, 'PUT');
}
});
});
</script>
<link rel="stylesheet" media="all" href="https://dz2cdn1.dzone.com/themes/dz20/ftl/colors.css">
<link rel="stylesheet" media="all" href="https://dz2cdn1.dzone.com/themes/dz20/ftl/article/styles.css">
<div id="body-container">
<div id="announcement-container-outer">
<div id="announcement-previous">
<i class="icon-angle-left"></i>
</div>
<div id="announcement-next">
<i class="icon-angle-right"></i>
</div>
<div id="announcement-container">
<div class="announcement announcement-count-1"
data-position="1">
<div class="body"><p><strong>Could your team report a vulnerability within 24 hours? </strong>Find out on September 23.</p></div>
<div class="spacer"></div>
<a href="https://cvent.me/O32zXR?utm_source=Announcements&amp;utm_medium=DzoneWeb&amp;utm_campaign=QtGroup-0923" target="_blank">
<button>Assess Your CRA Readiness</button>
</a>
</div>
</div>
</div>
<script type="text/javascript" async>
(function() {
let announcementPosition = 1;
let minAnnouncementPosition = -1;
let maxAnnouncementPosition = -1;
const announcementPrevBtn = document.querySelector('#announcement-previous');
const announcementNextBtn = document.querySelector('#announcement-next');
function withAnnouncements(callback) {
const announcements = document.querySelectorAll('#announcement-container .announcement');
for (let announcement of announcements) {
callback(announcement);
}
}
function initAnnouncementVars() {
document.querySelector(':root').style.setProperty('--mobile-announcement-separator-width', '1px');
withAnnouncements(function(announcement) {
const pos = parseInt(announcement.getAttribute('data-position'));
minAnnouncementPosition = minAnnouncementPosition === -1 ? pos : Math.min(minAnnouncementPosition, pos);
maxAnnouncementPosition = maxAnnouncementPosition === -1 ? pos : Math.max(maxAnnouncementPosition, pos);
});
if (document.querySelector('.announcementBarContainer')) {
document.querySelector(':root').style.setProperty('--body-top-padding', '0');
}
if (maxAnnouncementPosition <= 0) {
document.querySelector(':root').style.setProperty('--body-top-padding', '0');
}
sizeToFullWhenOneEntryOnMobile();
}
function setAnnouncementPosition(position) {
if (window.outerWidth >= 890) {
return; // we do not need to change the position, since we can display everything on desktop.
}
// Make the announcement cyclical
if (minAnnouncementPosition !== -1 && maxAnnouncementPosition !== -1) {
if (position > maxAnnouncementPosition) {
position = minAnnouncementPosition; // overflow to the first announcement
} else if (position < minAnnouncementPosition) {
position = maxAnnouncementPosition; // underflow to the last announcement
}
announcementPosition = position;
}
const shownAnnouncements = [];
let reverseFlex = false; // should only be true when the first and last items are showing
// Now that the position is valid, apply the transforms
withAnnouncements(function(announcement) {
const pos = parseInt(announcement.getAttribute('data-position'));
const isWrapped = position === maxAnnouncementPosition && pos === minAnnouncementPosition; // showing first + last at same time
const doesNextQualify = window.outerWidth >= 500 && (pos === position + 1 || isWrapped);
if (pos === position || doesNextQualify) {
shownAnnouncements.push(announcement);
} else {
announcement.style.display = 'none';
}
announcement.style.opacity = 0.0;
if (isWrapped) {
reverseFlex = true;
}
});
for (let announcement of shownAnnouncements) {
announcement.style.display = 'flex';
announcement.style.opacity = 1.0;
}
const announcementContainer = document.querySelector('#announcement-container');
if (announcementContainer) {
announcementContainer.style.flexDirection = reverseFlex ? 'row-reverse' : 'row';
}
}
function resetAnnouncements() {
announcementPosition = 1;
const announcementContainer = document.querySelector('#announcement-container');
if (announcementContainer) {
announcementContainer.style.flexDirection = 'row';
}
withAnnouncements(function(announcement) {
announcement.style.opacity = 1.0;
announcement.style.display = 'flex';
});
}
function sizeToFullWhenOneEntryOnMobile() {
if (maxAnnouncementPosition <= 2 && announcementPrevBtn && announcementNextBtn) {
announcementPrevBtn.style.display = maxAnnouncementPosition === 2 && window.outerWidth < 500 ? 'flex' : 'none';
announcementNextBtn.style.display = maxAnnouncementPosition === 2 && window.outerWidth < 500 ? 'flex' : 'none';
}
if (maxAnnouncementPosition === 1 && window.outerWidth >= 500 && window.outerWidth < 890) {
document.querySelector(':root').style.setProperty('--mobile-announcement-separator-width', '0');
document.querySelector('#announcement-container .announcement').style.maxWidth = '100%';
}
}
function resetAnnouncementsOnResize() {
announcementPosition = 1; // we want to reset the announcement position every resize
if (window.outerWidth >= 890) { // 4 announcements can be shown (215px * 4) + separator padding
resetAnnouncements();
} else { // if we're still on mobile, set the position to normalize things after resize
setAnnouncementPosition(announcementPosition);
sizeToFullWhenOneEntryOnMobile();
}
}
window.addEventListener('resize', resetAnnouncementsOnResize);
initAnnouncementVars();
setAnnouncementPosition(announcementPosition); // sets the min & max positions as well as initializes transforms
if (announcementPrevBtn) {
announcementPrevBtn.onclick = function() {
setAnnouncementPosition(announcementPosition - 1);
};
}
if (announcementNextBtn) {
announcementNextBtn.onclick = function() {
setAnnouncementPosition(announcementPosition + 1);
};
}
})(); </script>
<div id="ftl-article" class="trending-article-body">
<aside class="trending-sidebar" aria-labelledby="related-sidebar-heading">
<div class="trending">
<h2 id="related-sidebar-heading">Related</h2>
<div class="trending-separator"></div>
<ul>
<li class="item">
<a href="/articles/how-to-build-web-service-using-spring-boot-2x" class="related-link">How To Build Web Service Using Spring Boot 2.x</a>
</li>
<li class="item">
<a href="/articles/the-bill-you-didnt-see-coming" class="related-link">The Bill You Didn't See Coming</a>
</li>
<li class="item">
<a href="/articles/queues-dont-absorb-load-they-delay-bankruptcy-1" class="related-link">Why Queues Don’t Fix Scaling Problems</a>
</li>
<li class="item">
<a href="/articles/implement-hibernate-second-level-cache-with-ncache" class="related-link">Implement Hibernate Second-Level Cache With NCache</a>
</li>
</ul>
</div>
</aside>
<div class="container-fluid body trending-article-fluid">
<div class="row">
<div class="col-md-12">
<div class="articles-wrap">
<div class="ad-container">
<div id="div-gpt-ad-1435246566686-0" class="ads-billboard-article dz2_article_billboard_new" data-gpt-slot="top"></div>
</div>
<div class="article-stream widget-top-border">
<div class="article-main">
<div class="content-right-images">
<div id="div-gpt-ad-1435246566686-2" class="sidebar-ad dz2_article_halfpage_new" data-gpt-slot="sidebar1"></div>
<div class="trending-separator"></div>
<aside class="trending" aria-labelledby="trending-sidebar-heading">
<h2 id="trending-sidebar-heading">Trending</h2>
<ul>
<li class="item">
<a href="/articles/excel-dynamic-arrays-java" class="trending-link" target="_self">Dynamic Arrays, Spill, and LET: What Changed in Excel and Why It Matters for Java Applications</a>
</li>
<li class="item">
<a href="/articles/prevent-duplicate-api-calls" class="trending-link" target="_self">Prevent Duplicate API Calls With Idempotency: Patterns That Work</a>
</li>
<li class="item">
<a href="/articles/bottleneck-of-scaling" class="trending-link" target="_self">The Bottleneck of Scaling</a>
</li>
<li class="item">
<a href="/articles/performance-engineering-bottlenecks" class="trending-link" target="_self">How Performance Engineers Find and Fix Hidden System Bottlenecks</a>
</li>
</ul>
</aside>
</div>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Article",
"headline": "Load Testing WebDAV Servers",
"author": [{"image":{"@type":"ImageObject","caption":"George Maksimenko","url":"https://secure.gravatar.com/avatar/5baa61f784306be7e2cb75b3e7b5141d?d=identicon&r=PG"},"@type":"Person","worksFor":{"@type":"Organization","name":"BlazeMeter"},"name":"George Maksimenko","url":"https://dzone.com/users/3103373/georgemaksimenko.html"}],
"audience": "software developers",
"keywords": "performance testing,jmeter,webdav servers,load testing,performance",
"timeRequired": "PT8M",
"commentCount": 1,
"wordCount": "1989",
"accessMode": "textual, visual",
"datePublished": "2017-12-27T00:00:00Z",
"articleSection": "apm-tools-performance-monitoring-optimization",
"publisher": {
"@type": "Organization",
"name": "DZone",
"url": "https://dzone.com",
"logo": {
"@type": "ImageObject",
"url": "https://dzone.com/themes/dz20/images/dz_logo_2021_cropped.png"
}
},
"articleBody": "WebDAV is a set of extensions to the HTTP protocol, enabling more operations to resources. If you are using a WebDAV server, you should learn how to load test its unique abilities. This blog post will cover just that! We will explain how you can use Apache JMeter™ to load test COPY, MOVE, MKCOL, and more. Let's get started. WebDAV (\"Web-based Distributed Authoring and Versioning\") is a set of extensions to the HTTP protocol that allows clients to perform remote Web content authoring operations. Since WebDAV is an extension to the HTTP protocol, let's review a few things about the HTTP protocol first. HTTP stands for Hypertext Transfer Protocol. It is the most widely used protocol for communication over the World Wide Web. The HTTP protocol defines the following methods: GET, PUT, POST, OPTIONS, HEAD, TRACE, CONNECT, and DELETE. WebDAV adds the following new functionalities to HTTP: create, change and move resources (documents) on a server, namespace management (collections), management of properties about an author, modification of the date or anything else and overwrite protection. WebDAV extends HTTP without changing the existing functionality. The WebDAV protocol supports all HTTP methods and adds the following methods: MKCOL, COPY, MOVE, LOCK, UNLOCK, PROPPATCH, and PROPFIND. The list below displays the most commonly used HTTP and WebDAV methods. PUT - Upload new or update an old resource.GET - Read resource data.DELETE - Delete resources or collections.MKCOL - Create a collection.COPY - Copy resources or collections.MOVE - Move resources or collections.LOCK- Lock a resource or collection to avoid overwrite conflicts.UNLOCK - Unlock a locked resource or collection to make it available for writing.PROPPATCH - Manage properties defined on a resource.PROPFIND - Get property values from a resource. WebDAV Methods on JMeter JMeter supports all of these methods with the HTTP request sampler. So we don't need any plugins or extensions to work with WebDAV servers. However, we do need a WebDAV server to see how it works. I used a public service https://www.webdavserver.com/, which provides a free personal WebDAV server for testing purposes. While this service is free, they do ask that users keep their load testing to a reasonable size. Let's take this into account when we do our performance testing. Of course, if you have your own WebDAV server you can test as thoroughly as you would like. All WebDAV related methods can be divided into several groups: Resource management (PUT, GET), Namespace management (MKCOL, COPY, MOVE, DELETE), Lock management (LOCK, UNLOCK) and Properties management (PROPPATCH, PROPFIND). We will go over all of them. Let's get started. 1. Resource Management Standard HTTP methods allow you to read, write, and delete resources on a WebDAV server. Let's take a look at how to manage the documents below. PUT Method Writing content to a WebDAV server can be done in several ways by using an HTTP Request sample in JMeter. The first way is to send to the body of the resource with the Body Data option of the HTTP Request. Add an HTTP request sample and open the Body Data tab. Fill in the following values: Protocol: httpsServer Name or IP: www.webdavserver.comPort Number: 443Method: PUTPath: your_path/blazefile.txtBody data: BlazeMeter WebDAV blog postBlazeMeter WebDAV blog postBlazeMeter WebDAV blog postBlazeMeter WebDAV blog post After running this request, we can see the newly created blazefile.txt file in the web UI of the service. The text in the \"Body Data\" is what will appear in the file. Another way to write to resources is to use the Files Upload option of an HTTP request sample. Add an HTTP request sample and go to the Files Upload tab. Copy the web server values from the previous request. Fill in the following values: Method: PUTPath: your_path/blazefile.pdfFiles Upload: File path: /path_to_file/blazefile.pdfMIME Type: application/pdf We are able to upload any file from a local machine to the WebDAV server. I used a 1MB pdf file. GET Method Use the GET method to read resources from a WebDAV server. Add an HTTP request sample. Fill in the following values: Method: GETPath: your_path/blazefile.txt This request will show the content of the file in the response. You can verify this by using the View Results Tree listener. 2. Namespace Management The MKCOL, COPY, MOVE, and DELETE methods are designed to manage hierarchical namespaces (collections) that have resources located under those namespaces. MKCOL Method Requests with the MKCOL method will create an empty collection. Add an HTTP request sample and fill in the following fields. Required values: Method: MKCOLPath: your_path/blazecollection Execution of this request creates a blazecollection collection. You can check it by using the web UI. COPY Method You can use the copy operation for a single resource and for collections. Copying a collection will also copy all its nested collections and resources. NOTE: the destination location should be set in the HTTP header. To copy a single resource: Add an HTTP request sample. Fill in the following values: Method: COPYPath: your_path/blazefile.txt Add an HTTP Header Manager to the HTTP request sample to set the destination file for this resource. Add one row to this Config Element: Destination: https://www.webdavserver.com:443/your_path/blazefile_copy.txt After execution, a copy of the file will be placed in the same location as the copied file. Verify it by using the web UI. To copy a collection: Add another HTTP request or update the previous request to copy a collection. Fill in the following values: Method: COPYPath: your_path/blazecollection Type in the collection destination instead of the location of a particular resource. Add an HTTP Header Manager and also set the destination location. Add one row: Destination: https://www.webdavserver.com:443/your_path/blazecollection_copy This request will copy the whole collection, together with its nested elements, to a new place. MOVE Method The move operation is also possible for single resources as well as collections. Moving a collection will move all of its nested collections and resources. NOTE: the destination location should be sent to the server in the HTTP header. To move a single resource: Use an HTTP request sample just like our other requests. Fill in the following values: Method: MOVEPath: your_path/blazefile.txt The document specified in the path field is a source document and will be deleted after successfully moving it to a new location. Add an HTTP Header Manager to the HTTP request sample. Add a row to this Config Element: Destination: https://www.webdavserver.com:443/your_path/blazefile_move.txt The Blazefile.txt will be moved to blazefile_move.txt after execution of this request. How to move a collection: Add an HTTP request sample or update the previous one. Fill in the following values: Method: MOVEPath: your_path/blazecollection Add an HTTP Header Manager to the HTTP request sample. Set the destination in the HTTP Header Manager: Destination: https://www.webdavserver.com:443/your_path/blazecollection_move This request will move the whole collection along with its nested elements to a new place. DELETE Method A delete request will destroy a single resource or collection with all of its nested collections and resources. To delete a single resource: Add an HTTP request sample. Fill in the required values: Method: DELETEPath: your_path/blazefile.txt This request will delete the blazefile.txt resource from the WebDAV server. To delete a collection: To delete a collection add a HTTP request sample. Fill in the following values: Method: DELETEPath: your_path/blazecollection Execution of this sample will delete the entire collection including all nested elements. 3. Lock Management Locking resources is necessary to avoid problems with overwriting conflicts between concurrently active users. It is common practice when an author makes an exclusive lock before writing an object and unlocking it after editing is done. WebDAV allows two kinds of locks: shared locks and exclusive locks. Locking is available for single resources and for collections. Let's see how to lock a single resource below. LOCK Method Add an HTTP request sample as usual. Required values: Method: LOCKPath: your_path/blazefile.txtBody Data: &lt;?xml version=\"1.0\" encoding=\"utf-8\"?&gt; &lt;lockinfo xmlns='DAV:'&gt; &lt;lockscope&gt;&lt;exclusive/&gt;&lt;/lockscope&gt; &lt;locktype&gt;&lt;write/&gt;&lt;/locktype&gt;&lt;owner&gt;BlazeMeter&lt;/owner&gt; &lt;/lockinfo&gt; This is an example of an exclusive lock. This type of lock is important because some servers support only exclusive locks. Run this request and check the response. The response contains a lock token which is necessary to send as an HTTP header with an UNLOCK request to pass authorization. Add an XPath Extractor to the HTTP Request to retrieve the token. Fill in the following values: Reference Name: locktokenXPath query: //*[name()='d:locktoken']/*[name() = 'd:href']Default Value: ERROR The lock token will be saved to the locktoken variable and we will be able to use it to unlock the request. UNLOCK Method To unlock a request add an HTTP request sample. Required values: Method: UNLOCKPath: your_path/blazefile.txt Add an HTTP Header manager to send the lock token as an HTTP header. Add row: Lock-Token &lt;${locktoken}&gt; The execution of this request should unlock the file for future changes by other authors. 4. Properties Management WebDAV has two kinds of properties: live properties and dead properties. A live property is a property that is determined and managed by the server. Each resource has a fixed number of live properties. For example, the live \"getlastmodified\" property presents the last modification time. This value is automatically updated by the server each time a resource changes. A dead property, on the other hand, is a property that is determined and managed by the user. The server only records the value of this property. For example, the dead \"version\" property contains the version of the current document. The user is responsible for updating the value of these properties. PROPPATCH Method Let's see how to set dead properties via JMeter. Add an HTTP Request sample. Fill in the following values: Method: PROPPATCHPath: your_path/blazefile.txtBody Data: &lt;?xml version=\"1.0\" encoding=\"utf-8\" ?&gt; &lt;D:propertyupdate xmlns:D=\"DAV:\"&gt; &lt;D:set&gt;&lt;D:prop&gt;&lt;prop0 xmlns=\"https://www.blazemeter.com/\"&gt;blazevalue0&lt;/prop0&gt;&lt;/D:prop&gt;&lt;/D:set&gt; &lt;D:set&gt;&lt;D:prop&gt;&lt;prop1 xmlns=\"https://www.blazemeter.com/\"&gt;blazevalue1&lt;/prop1&gt;&lt;/D:prop&gt;&lt;/D:set&gt; &lt;D:set&gt;&lt;D:prop&gt;&lt;prop2 xmlns=\"https://www.blazemeter.com/\"&gt;blazevalue2&lt;/prop2&gt;&lt;/D:prop&gt;&lt;/D:set&gt; &lt;/D:propertyupdate&gt; Run this request to assign three dead properties (prop0, prop1, prop2) to the blazefile.txt file. PROPFIND Method Reading dead or live properties can be accomplished by using the PROPFIND request. To read dead properties: Add an HTTP Request sample. Fill in the following values: Method: PROPFINDPath: your_path/blazefile.txtBody Data: &lt;?xml version=\"1.0\" encoding=\"utf-8\"?&gt; &lt;propfind xmlns=\"DAV:\"&gt;&lt;prop&gt; &lt;prop0 xmlns=\"https://www.blazemeter.com/\"/&gt; &lt;prop1 xmlns=\"https://www.blazemeter.com/\"/&gt; &lt;prop2 xmlns=\"https://www.blazemeter.com/\"/&gt; &lt;/prop&gt;&lt;/propfind&gt; Execute the sample and see the response. The response contains a list of asked properties with their values. To read live properties: Add an HTTP Request sample. Fill in the following values: Method: PROPFINDPath: your_path/blazefile.txtBody Data: &lt;?xml version=\"1.0\" encoding=\"utf-8\"?&gt; &lt;propfind xmlns=\"DAV:\"&gt;&lt;prop&gt; &lt;creationdate xmlns=\"DAV:\"/&gt; &lt;getlastmodified xmlns=\"DAV:\"/&gt; &lt;resourcetype xmlns=\"DAV:\"/&gt; &lt;supportedlock xmlns=\"DAV:\"/&gt; &lt;lockdiscovery xmlns=\"DAV:\"/&gt; &lt;getcontentlength xmlns=\"DAV:\"/&gt; &lt;getetag xmlns=\"DAV:\"/&gt; &lt;getcontentlanguage xmlns=\"DAV:\"/&gt; &lt;getcontenttype xmlns=\"DAV:\"/&gt; &lt;supportedlock xmlns=\"DAV:\"/&gt; &lt;/prop&gt;&lt;/propfind&gt; Check the response after running the request. The response contains all of the requested properties with the actual values. Script and Test Run Now let's create a simple script to run a performance test on the WebDAV server to see how it goes. Download the JMX file from here. Here is a short description of the test script: MKCOL: Create a 'blazecollection' collection.PUT: Put 1MB file ('blazefile.pdf') in this collection.PROPPATCH: Set dead properties to file 'blazefile.pdf.'PROPFIND: Get dead properties from the 'blazefile.pdf' file.PROPFIND: Get live properties from the 'blazefile.pdf' file.COPY: Copy 'blazefile.pdf' file to 'blazefile_copy.pdf' file.MOVE: Move 'blazefile_copy.pdf' to 'blazefile_move.pdf.'LOCK: Lock 'blazefile.pdf' file.UNLOCK: Unlock 'blazefile.pdf' file.DELETE: Delete 'blazecollection' collection. This script can be compiled from the samples that we learned in this blog post above with some minor changes. Collections should have unique names to avoid conflicts with other virtual users. This can be accomplished by adding the Thread Number to the name of each collection. An example of a collection name: blazecollection${__threadNum}. I have created a Thread Group with the following parameters: Number of Threads is 10; Ramp-up period is 10 seconds; Loop count is 10. Let's keep in mind that WebDAV service holders asked that we keep the load to a reasonable size. The results of the test run are presented in the Aggregate Report below. As you can see, we can draw some conclusions. This WebDAV server can work with 10 active users simultaneously. Uploading a 1MB file will take about 4 seconds. Locking is slower than unlocking, etc. That's it! Now you can start writing your own awesome WebDAV server script. To learn more JMeter, check out our free JMeter academy with advanced and basic courses.",
"mainEntityOfPage": {
"@type": "WebPage",
"@id": "https://dzone.com/articles/load-testing-webdav-servers"
},
"image": {
"@type": "ImageObject",
"url": "https://dz2cdn1.dzone.com/storage/article-thumb/7625812-thumb.jpg"
}
}
</script>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "BreadcrumbList",
"itemListElement": [
{
"@type": "ListItem",
"position": 1,
"name": "DZone",
"item": "https://dzone.com"
},
{
"@type": "ListItem",
"position": 2,
"name": "Data Engineering",
"item": "https://dzone.com/data-engineering"
},
{
"@type": "ListItem",
"position": 3,
"name": "Databases",
"item": "https://dzone.com/databases"
},
{
"@type": "ListItem",
"position": 4,
"name": "Load Testing WebDAV Servers",
"item": "https://dzone.com/articles/load-testing-webdav-servers"
}
]
}
</script>
<article>
<div class="content">
<div class="header">
<ol class="breadcrumb">
<li class="server"><a href="https://dzone.com">DZone</a></li>
<li class="server"><a href="https://dzone.com/data-engineering">Data Engineering</a></li>
<li class="server"><a href="https://dzone.com/databases">Databases</a></li>
<li class="active server">Load Testing WebDAV Servers</li>
</ol>
<div class="header-title">
<div class="title">
<h1 class="article-title">Load Testing WebDAV Servers</h1>
</div>
<div class="subhead">
<p>In this post, we'll give a tutorial that covers how to load test the unique abilities of the WebDAV server that are working on.</p>
</div>
<div class="publish-meta">
By<span style="user-select: none;">&nbsp;</span>
<div class="article-author-meta">
<img src="https://secure.gravatar.com/avatar/5baa61f784306be7e2cb75b3e7b5141d?d=identicon&r=PG" class="avatar" alt="George Maksimenko user avatar" width="40">
<div class="author-info">
<span class="author-name">
<a href="/users/3103373/georgemaksimenko.html" rel="nofollow" data-core-user="false">George Maksimenko</a>
</span>
</div>
<div class="mvb-award">
<i title="Most Valuable Blogger" class="icon-mvb-1"></i>
</div>
&middot;
</div>
<span class="author-date">
Dec. 27, 17
</span>
&middot;
<span>Tutorial</span>
</div>
</div>
</div>
<div class="author-n-useraction">
<div class="like action" x-data="engagementModal(articleId)">
<span id="activity-like-icon" class="dz-like icon-thumbs-up" x-on:click="updateStore()"></span>
<span class="action-label like-text" x-on:click="open()" x-cloak>
<span>Likes</span>
<span id="activity-like-counter" class="like-count">(1)</span>
</span>
<template x-teleport="body">
<div class="engagement-overlay" x-show="$store.article.engagement.open && nodeId === $store.article.id" x-on:keyup.escape.window="close()">
<div class="engagement-modal">
<div class="inner" x-on:click.outside="close()">
<div class="header">
<div class="title">Likes</div>
<button class="close" x-on:click="close()"></button>
</div>
<div class="content">
<div x-show="$store.article.engagement.initializing" class="loading-screen">
<i class="icon icon-spin3 anim-spin"></i>
</div>
<div x-show="!$store.article.engagement.initializing">
<template x-for="user in $store.article.engagement.users" :key="user.id">
<div class="media">
<div class="media-left">
<img class="avatar"
x-bind:src="user.profile.profileImage"
loading="lazy"
width="50"
height="50"
>
</div>
<div class="media-right">
<a x-bind:href="user.computed.url" x-html="user.profile.name"></a>
<div x-show="formatJobData(user)" x-html="formatJobData(user)"></div>
</div>
</div>
</template>
</div>
<div x-show="isDataUnavailable()" class="center-screen">
<div x-show="!$store.article.engagement.unauthorized">
<div>There are no likes...yet! &#128064;</div>
<div>Be the first to like this post!</div>
</div>
<div x-show="$store.article.engagement.unauthorized">
<div>It looks like you're not logged in.</div>
<div><a href="/users/login.html">Sign in</a> to see who liked this post!</div>
</div>
</div>
<div x-show="isFooterShowing()">
<div class="footer">
<button class="btn btn-primary" x-on:click="fetchEngagements()"
x-bind:disabled="$store.article.engagement.loading"
>
Load More
<i x-show="$store.article.engagement.loading" class="icon icon-spin3 anim-spin"></i>
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</template> </div>
<div class="action comment-action">
<span class="comment">
<i class="icon-comment"></i>
<span class="action-label">Comment</span>
<span id="activity-comment-counter" class="comment-count"></span>
</span>
</div>
<div class="save action">
<div id="activity-save-icon" class="save icon-star-empty">
<span id="activity-save-text" class="action-label">Save</span>
</div>
</div>
<div class="tweet action">
<a id="tweet-link" href="" class="title" target="_blank">
<span><i class="icon-twitter"></i></span>
<span class="action-label">Tweet</span>
</a>
</div>
<div class="linkedin action">
<a id="linkedin-link" href="https://www.linkedin.com/sharing/share-offsite/?url=https://dzone.com/articles/load-testing-webdav-servers" class="title" target="_blank">
<span><i class="icon-linkedin-1"></i></span>
<span class="action-label">Share</span>
</a>
</div>
<div class="right-most">
<div id="activity-view-container" class="article-views action">
<i class="icon-eye"></i>
<span class="action-label view-count">10.1K Views</span>
</div>
</div>
</div>
<div class="signin-prompt">
<p>Join the DZone community and get the full member experience.</p>
<a id="article-signin-prompt" href="/static/registration.html">Join For Free</a>
</div>
<div class="arrow-down"></div>
<div id="top-bumper-container"></div>
<div>
<div class="content-html"><p pid="2">WebDAV is a set of extensions to the HTTP protocol, enabling more operations to resources. If you are using a WebDAV server, you should learn how to load test its unique abilities. This blog post will cover just that! We will explain how you can use <a href="http://jmeter.apache.org" target="_blank">Apache JMeter™</a> to load test COPY, MOVE, MKCOL, and more. Let's get started.</p>
<p pid="3">WebDAV (&quot;Web-based Distributed Authoring and Versioning&quot;) is a set of extensions to the HTTP protocol that allows clients to perform remote Web content authoring operations.</p>
<p pid="4">Since WebDAV is an extension to the HTTP protocol, let's review a few things about the HTTP protocol first.</p>
<p pid="5">HTTP stands for Hypertext Transfer Protocol. It is the most widely used protocol for communication over the World Wide Web. The HTTP protocol defines the following methods: GET, PUT, POST, OPTIONS, HEAD, TRACE, CONNECT, and DELETE.</p>
<p pid="6">WebDAV adds the following new functionalities to HTTP: create, change and move resources (documents) on a server, namespace management (collections), management of properties about an author, modification of the date or anything else and overwrite protection. WebDAV extends HTTP without changing the existing functionality. The WebDAV protocol supports all HTTP methods and adds the following methods: MKCOL, COPY, MOVE, LOCK, UNLOCK, PROPPATCH, and PROPFIND.</p>
<p pid="7">The list below displays the most commonly used HTTP and WebDAV methods.</p>
<ul>
<li><strong>PUT</strong> - Upload new or update an old resource.</li>
<li><strong>GET</strong> - Read resource data.</li>
<li><strong>DELETE</strong> - Delete resources or collections.</li>
<li><strong>MKCOL</strong> - Create a collection.</li>
<li><strong>COPY</strong> - Copy resources or collections.</li>
<li><strong>MOVE</strong> - Move resources or collections.</li>
<li><strong>LOCK</strong>- Lock a resource or collection to avoid overwrite conflicts.</li>
<li><strong>UNLOCK</strong> - Unlock a locked resource or collection to make it available for writing.</li>
<li><strong>PROPPATCH</strong> - Manage properties defined on a resource.</li>
<li><strong>PROPFIND</strong>&nbsp;- Get property values from a resource.</li>
</ul>
<h3>WebDAV Methods on JMeter</h3>
<p pid="8"><a href="http://www.blazemeter.com/jmeter-load-testing?utm_source=blog&amp;utm_medium=BM_blog&amp;utm_campaign=load-testing-webdav-servers" target="_blank">JMeter</a> supports all of these methods with the HTTP request sampler. So we don't need any plugins or extensions to work with WebDAV servers.</p>
<p pid="9">However, we do need a WebDAV server to see how it works. I used a public service <a href="https://www.webdavserver.com/">https://www.webdavserver.com/</a>, which provides a free personal WebDAV server for testing purposes.</p>
<p pid="10">While this service is free, they do ask that users keep their load testing to a reasonable size. Let's take this into account when we do our performance testing.</p>
<p pid="11">Of course, if you have your own WebDAV server you can test as thoroughly as you would like.</p>
<p pid="12">All WebDAV related methods can be divided into several groups: Resource management (PUT, GET), Namespace management (MKCOL, COPY, MOVE, DELETE), Lock management (LOCK, UNLOCK) and Properties management (PROPPATCH, PROPFIND). We will go over all of them. Let's get started.</p>
<h3>1. Resource Management</h3>
<p pid="13">Standard HTTP methods allow you to read, write, and delete resources on a WebDAV server. Let's take a look at how to manage the documents below.</p>
<h4>PUT Method</h4>
<p pid="14">Writing content to a WebDAV server can be done in several ways by using an HTTP Request sample in JMeter.</p>
<p pid="15">The first way is to send to the body of the resource with the Body Data option of the HTTP Request.</p>
<p pid="16">Add an HTTP request sample and open the Body Data tab.</p>
<p pid="114"><img class="fr-fin fr-dib" src="https://cdn2.hubspot.net/hubfs/208250/Blog_Images/webdav1.png" /></p>
<p pid="17">Fill in the following values:</p>
<ul>
<li>Protocol:&nbsp;<em>https</em></li>
<li>Server Name or IP:<em>&nbsp;<a href="http://www.webdavserver.com/" target="_blank">www.webdavserver.com</a></em></li>
<li>Port Number:&nbsp;<em>443</em></li>
<li>Method:&nbsp;<em>PUT</em></li>
<li>Path:&nbsp;<em>your_path/blazefile.txt</em></li>
<li>Body data:
<ul>
<li><em>BlazeMeter WebDAV blog post</em></li>
<li><em>BlazeMeter WebDAV blog post</em></li>
<li><em>BlazeMeter WebDAV blog post</em></li>
<li><em>BlazeMeter WebDAV blog post</em></li>
</ul></li>
</ul>
<p pid="18">After running this request, we can see the newly created <em>blazefile.txt</em> file in the web UI of the service. The text in the &quot;Body Data&quot; is what will appear in the file.</p>
<p pid="19">Another way to write to resources is to use the Files Upload option of an HTTP request sample.</p>
<p pid="20">Add an HTTP request sample and go to the Files Upload tab. Copy the web server values from the previous request.</p>
<p pid="115"><img class="fr-fin fr-dib" src="https://cdn2.hubspot.net/hubfs/208250/Blog_Images/webdav2.png" /></p>
<p pid="21">Fill in the following values:</p>
<ul>
<li>Method:&nbsp;<em>PUT</em></li>
<li>Path:&nbsp;<em>your_path/blazefile.pdf</em></li>
<li>Files Upload:
<ul>
<li>File path: <em>/path_to_file/blazefile.pdf</em></li>
<li>MIME Type: <em>application/pdf</em></li>
</ul></li>
</ul>
<p pid="23">We are able to upload any file from a local machine to the WebDAV server. I used a 1MB pdf file.</p>
<h4>GET Method</h4>
<p pid="24">Use the GET method to read resources from a WebDAV server.</p>
<p pid="25">Add an HTTP request sample.</p>
<p pid="116"><img class="fr-fin fr-dib" src="https://cdn2.hubspot.net/hubfs/208250/Blog_Images/webdav3.png" /></p>
<p pid="26">Fill in the following values:</p>
<ul>
<li>Method:&nbsp;<em>GET</em></li>
<li>Path:&nbsp;<em>your_path/blazefile.txt</em></li>
</ul>
<p pid="27">This request will show the content of the file in the response. You can verify this by using the View Results Tree listener.</p>
<h3>2. Namespace Management</h3>
<p pid="28">The MKCOL, COPY, MOVE, and DELETE methods are designed to manage hierarchical namespaces (collections) that have resources located under those namespaces.</p>
<h4>MKCOL Method</h4>
<p pid="29">Requests with the MKCOL method will create an empty collection.</p>
<p pid="30">Add an HTTP request sample and fill in the following fields.</p>
<p pid="117"><img class="fr-fin fr-dib" src="https://cdn2.hubspot.net/hubfs/208250/Blog_Images/webdav4.png" /></p>
<p pid="31">Required values:</p>
<ul>
<li>Method:&nbsp;<em>MKCOL</em></li>
<li>Path:&nbsp;<em>your_path/blazecollection</em></li>
</ul>
<p pid="32">Execution of this request creates a <em>blazecollection</em> collection. You can check it by using the web UI.</p>
<h4>COPY Method</h4>
<p pid="33">You can use the copy operation for a single resource and for collections. Copying a collection will also copy all its nested collections and resources.</p>
<p pid="34">NOTE: the destination location should be set in the HTTP header.</p>
<p pid="35">To copy a single resource:</p>
<p pid="36">Add an HTTP request sample.</p>
<p pid="118"><img class="fr-fin fr-dib" src="https://cdn2.hubspot.net/hubfs/208250/Blog_Images/webdav5.png" /></p>
<p pid="37">Fill in the following values:</p>
<ul>
<li>Method:&nbsp;<em>COPY</em></li>
<li>Path:&nbsp;<em>your_path/blazefile.txt</em></li>
</ul>
<p pid="38">Add an HTTP Header Manager to the HTTP request sample to set the destination file for this resource.</p>
<p pid="119"><img class="fr-fin fr-dib" src="https://cdn2.hubspot.net/hubfs/208250/Blog_Images/webdav6.png" /></p>
<p pid="39">Add one row to this Config Element: <em>Destination: https://www.webdavserver.com:443/your_path/blazefile_copy.txt</em></p>
<p pid="40">After execution, a copy of the file will be placed in the same location as the copied file. Verify it by using the web UI.</p>
<p pid="41">To copy a collection:</p>
<p pid="42">Add another HTTP request or update the previous request to copy a collection.</p>
<p pid="120"><img class="fr-fin fr-dib" src="https://cdn2.hubspot.net/hubfs/208250/Blog_Images/webdav7.png" /></p>
<p pid="43">Fill in the following values:</p>
<ul>
<li>Method:&nbsp;<em>COPY</em></li>
<li>Path:&nbsp;<em>your_path/blazecollection</em></li>
</ul>
<p pid="44">Type in the collection destination instead of the location of a particular resource.</p>
<p pid="45">Add an HTTP Header Manager and also set the destination location.</p>
<p pid="121"><img class="fr-fin fr-dib" src="https://cdn2.hubspot.net/hubfs/208250/Blog_Images/webdav8.png" /></p>
<p pid="46">Add one row: <em>Destination: https://www.webdavserver.com:443/your_path/blazecollection_copy</em></p>
<p pid="47">This request will copy the whole collection, together with its nested elements, to a new place.</p>
<h4>MOVE Method</h4>
<p pid="48">The move operation is also possible for single resources as well as collections. Moving a collection will move all of its nested collections and resources.</p>
<p pid="49">NOTE: the destination location should be sent to the server in the HTTP header.</p>
<p pid="50">To move a single resource:</p>
<p pid="51">Use an HTTP request sample just like our other requests.</p>
<p pid="122"><img class="fr-fin fr-dib" src="https://cdn2.hubspot.net/hubfs/208250/Blog_Images/webdav9.png" /></p>
<p pid="52">Fill in the following values:</p>
<ul>
<li>Method:&nbsp;<em>MOVE</em></li>
<li>Path:&nbsp;<em>your_path/blazefile.txt</em></li>
</ul>
<p pid="53">The document specified in the path field is a source document and will be deleted after successfully moving it to a new location.</p>
<p pid="54">Add an HTTP Header Manager to the HTTP request sample.</p>
<p pid="123"><img class="fr-fin fr-dib" src="https://cdn2.hubspot.net/hubfs/208250/Blog_Images/webdav10.png" /></p>
<p pid="55">Add a row to this Config Element: <em>Destination: https://www.webdavserver.com:443/your_path/blazefile_move.txt</em></p>
<p pid="56">The <em>Blazefile.txt</em> will be moved to <em>blazefile_move.txt</em> after execution of this request.</p>
<p pid="57">How to move a collection:</p>
<p pid="58">Add an HTTP request sample or update the previous one.</p>
<p pid="124"><img class="fr-fin fr-dib" src="https://cdn2.hubspot.net/hubfs/208250/Blog_Images/webdav11.png" /></p>
<p pid="59">Fill in the following values:</p>
<ul>
<li>Method:&nbsp;<em>MOVE</em></li>
<li>Path:&nbsp;<em>your_path/blazecollection</em></li>
</ul>
<p pid="60">Add an HTTP Header Manager to the HTTP request sample.</p>
<p pid="125"><img class="fr-fin fr-dib" src="https://cdn2.hubspot.net/hubfs/208250/Blog_Images/webdav12.png" /></p>
<p pid="61">Set the destination in the HTTP Header Manager: <em>Destination: https://www.webdavserver.com:443/your_path/blazecollection_move</em></p>
<p pid="62">This request will move the whole collection along with its nested elements to a new place.</p>
<h4>DELETE Method</h4>
<p pid="63">A delete request will destroy a single resource or collection with all of its nested collections and resources.</p>
<p pid="64">To delete a single resource:</p>
<p pid="65">Add an HTTP request sample.</p>
<p pid="126"><img class="fr-fin fr-dib" src="https://cdn2.hubspot.net/hubfs/208250/Blog_Images/webdav13.png" /></p>
<p pid="66">Fill in the required values:</p>
<ul>
<li>Method:&nbsp;<em>DELETE</em></li>
<li>Path:&nbsp;<em>your_path/blazefile.txt</em></li>
</ul>
<p pid="67">This request will delete the <em>blazefile.txt</em> resource from the WebDAV server.</p>
<p pid="68">To delete a collection:</p>
<p pid="69">To delete a collection add a HTTP request sample.</p>
<p pid="127"><img class="fr-fin fr-dib" src="https://cdn2.hubspot.net/hubfs/208250/Blog_Images/webdav14.png" /></p>
<p pid="70">Fill in the following values:</p>
<ul>
<li>Method:&nbsp;<em>DELETE</em></li>
<li>Path:&nbsp;<em>your_path/blazecollection</em></li>
</ul>
<p pid="149">Execution of this sample will delete the entire collection including all nested elements.</p>
<h3>3. Lock Management</h3>
<p pid="72">Locking resources is necessary to avoid problems with overwriting conflicts between concurrently active users. It is common practice when an author makes an exclusive lock before writing an object and unlocking it after editing is done. WebDAV allows two kinds of locks: shared locks and exclusive locks.</p>
<p pid="73">Locking is available for single resources and for collections. Let's see how to lock a single resource below.</p>
<h4>LOCK Method</h4>
<p pid="74">Add an HTTP request sample as usual.</p>
<p pid="128"><img class="fr-fin fr-dib" src="https://cdn2.hubspot.net/hubfs/208250/Blog_Images/webdav15.png" /></p>
<p pid="75">Required values:</p>
<ul>
<li>Method:&nbsp;<em>LOCK</em></li>
<li>Path:<em>&nbsp;your_path/blazefile.txt</em></li>
<li>Body Data:</li>
</ul>
<pre><code lang="application/xml">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;lockinfo xmlns='DAV:'&gt;
&lt;lockscope&gt;&lt;exclusive/&gt;&lt;/lockscope&gt;
&lt;locktype&gt;&lt;write/&gt;&lt;/locktype&gt;&lt;owner&gt;BlazeMeter&lt;/owner&gt;
&lt;/lockinfo&gt;</code></pre>
<p pid="153">This is an example of an exclusive lock. This type of lock is important because some servers support only exclusive locks.</p>
<p pid="77">Run this request and check the response.</p>
<p pid="129"><img class="fr-fin fr-dib" src="https://cdn2.hubspot.net/hubfs/208250/Blog_Images/webdav16.png" /></p>
<p pid="78">The response contains a lock token which is necessary to send as an HTTP header with an UNLOCK request to pass authorization.</p>
<p pid="79">Add an XPath Extractor to the HTTP Request to retrieve the token.</p>
<p pid="130"><img class="fr-fin fr-dib" src="https://cdn2.hubspot.net/hubfs/208250/Blog_Images/webdav17.png" /></p>
<p pid="80">Fill in the following values:</p>
<ul>
<li>Reference Name: <em>locktoken</em></li>
<li>XPath query:<em> //*[name()='d:locktoken']/*[name() = 'd:href']</em></li>
<li>Default Value: <em>ERROR</em></li>
</ul>
<p pid="81">The lock token will be saved to the <em>locktoken</em> variable and we will be able to use it to unlock the request.</p>
<h4>UNLOCK Method</h4>
<p pid="82">To unlock a request add an HTTP request sample.</p>
<p pid="131"><img class="fr-fin fr-dib" src="https://cdn2.hubspot.net/hubfs/208250/Blog_Images/webdav18.png" /></p>
<p pid="83">Required values:</p>
<ul>
<li>Method:&nbsp;<em>UNLOCK</em></li>
<li>Path:&nbsp;<em>your_path/blazefile.txt</em></li>
</ul>
<p pid="84">Add an HTTP Header manager to send the lock token as an HTTP header.</p>
<p pid="132"><img class="fr-fin fr-dib" src="https://cdn2.hubspot.net/hubfs/208250/Blog_Images/webdav19.png" /></p>
<p pid="85">Add row: <em>Lock-Token &lt;${locktoken}&gt;</em></p>
<p pid="86">The execution of this request should unlock the file for future changes by other authors.</p>
<h3>4. Properties Management</h3>
<p pid="87">WebDAV has two kinds of properties: live properties and dead properties. A live property is a property that is determined and managed by the server. Each resource has a fixed number of live properties. For example, the live &quot;getlastmodified&quot; property presents the last modification time. This value is automatically updated by the server each time a resource changes. A dead property, on the other hand, is a property that is determined and managed by the user. The server only records the value of this property. For example, the dead &quot;version&quot; property contains the version of the current document. The user is responsible for updating the value of these properties.</p>
<h4>PROPPATCH Method</h4>
<p pid="88">Let's see how to set dead properties via JMeter.</p>
<p pid="89">Add an HTTP Request sample.</p>
<p pid="133"><img class="fr-fin fr-dib" src="https://cdn2.hubspot.net/hubfs/208250/Blog_Images/webdav20.png" /></p>
<p pid="90">Fill in the following values:</p>
<ul>
<li>Method:&nbsp;<em>PROPPATCH</em></li>
<li>Path:&nbsp;<em>your_path/blazefile.txt</em></li>
<li>Body Data:</li>
</ul>
<pre><code lang="application/xml">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot; ?&gt;
&lt;D:propertyupdate xmlns:D=&quot;DAV:&quot;&gt;
&lt;D:set&gt;&lt;D:prop&gt;&lt;prop0 xmlns=&quot;https://www.blazemeter.com/&quot;&gt;blazevalue0&lt;/prop0&gt;&lt;/D:prop&gt;&lt;/D:set&gt;
&lt;D:set&gt;&lt;D:prop&gt;&lt;prop1 xmlns=&quot;https://www.blazemeter.com/&quot;&gt;blazevalue1&lt;/prop1&gt;&lt;/D:prop&gt;&lt;/D:set&gt;
&lt;D:set&gt;&lt;D:prop&gt;&lt;prop2 xmlns=&quot;https://www.blazemeter.com/&quot;&gt;blazevalue2&lt;/prop2&gt;&lt;/D:prop&gt;&lt;/D:set&gt;
&lt;/D:propertyupdate&gt;</code></pre>
<p pid="158">Run this request to assign three dead properties (prop0, prop1, prop2) to the <em>blazefile.txt</em> file.</p>
<h4>PROPFIND Method</h4>
<p pid="92">Reading dead or live properties can be accomplished by using the PROPFIND request.</p>
<p pid="93">To read dead properties:</p>
<p pid="94">Add an HTTP Request sample.</p>
<p pid="134"><img class="fr-fin fr-dib" src="https://cdn2.hubspot.net/hubfs/208250/Blog_Images/webdav21.png" /></p>
<p pid="95">Fill in the following values:</p>
<ul>
<li>Method:&nbsp;<em>PROPFIND</em></li>
<li>Path:&nbsp;<em>your_path/blazefile.txt</em></li>
<li>Body Data:</li>
</ul>
<pre><code lang="application/xml">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;propfind xmlns=&quot;DAV:&quot;&gt;&lt;prop&gt;
&lt;prop0 xmlns=&quot;https://www.blazemeter.com/&quot;/&gt;
&lt;prop1 xmlns=&quot;https://www.blazemeter.com/&quot;/&gt;
&lt;prop2 xmlns=&quot;https://www.blazemeter.com/&quot;/&gt;
&lt;/prop&gt;&lt;/propfind&gt;</code></pre>
<p pid="162">Execute the sample and see the response.</p>
<p pid="135"><img class="fr-image-dropped fr-fin fr-dib" src="https://cdn2.hubspot.net/hubfs/208250/Blog_Images/webdav22.png" /></p>
<p pid="97">The response contains a list of asked properties with their values.</p>
<p pid="98">To read live properties:</p>
<p pid="99">Add an HTTP Request sample.</p>
<p pid="136"><img class="fr-fin fr-dib" src="https://cdn2.hubspot.net/hubfs/208250/Blog_Images/webdav23.png" /></p>
<p pid="100">Fill in the following values:</p>
<ul>
<li>Method:&nbsp;<em>PROPFIND</em></li>
<li>Path:&nbsp;<em>your_path/blazefile.txt</em></li>
<li>Body Data:</li>
</ul>
<pre><code lang="application/xml">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;propfind xmlns=&quot;DAV:&quot;&gt;&lt;prop&gt;
&lt;creationdate xmlns=&quot;DAV:&quot;/&gt;
&lt;getlastmodified xmlns=&quot;DAV:&quot;/&gt;
&lt;resourcetype xmlns=&quot;DAV:&quot;/&gt;
&lt;supportedlock xmlns=&quot;DAV:&quot;/&gt;
&lt;lockdiscovery xmlns=&quot;DAV:&quot;/&gt;
&lt;getcontentlength xmlns=&quot;DAV:&quot;/&gt;
&lt;getetag xmlns=&quot;DAV:&quot;/&gt;
&lt;getcontentlanguage xmlns=&quot;DAV:&quot;/&gt;
&lt;getcontenttype xmlns=&quot;DAV:&quot;/&gt;
&lt;supportedlock xmlns=&quot;DAV:&quot;/&gt;
&lt;/prop&gt;&lt;/propfind&gt;</code></pre>
<p pid="166">Check the response after running the request.</p>
<p pid="137"><img class="fr-fin fr-dib" src="https://cdn2.hubspot.net/hubfs/208250/Blog_Images/webdav24.png" /></p>
<p pid="102">The response contains all of the requested properties with the actual values.</p>
<h3 pid="167">Script and Test Run</h3>
<p pid="103">Now let's create a simple script to run a performance test on the WebDAV server to see how it goes. <a href="https://www.blazemeter.com/blog/load-testing-webdav-servers" target="_blank">Download the JMX file from here.</a></p>
<p pid="104">Here is a short description of the test script:</p>
<ol>
<li>MKCOL: Create a 'blazecollection' collection.</li>
<li>PUT: Put 1MB file ('blazefile.pdf') in this collection.</li>
<li>PROPPATCH: Set dead properties to file 'blazefile.pdf.'</li>
<li>PROPFIND: Get dead properties from the 'blazefile.pdf' file.</li>
<li>PROPFIND: Get live properties from the 'blazefile.pdf' file.</li>
<li>COPY: Copy 'blazefile.pdf' file to 'blazefile_copy.pdf' file.</li>
<li>MOVE: Move 'blazefile_copy.pdf' to 'blazefile_move.pdf.'</li>
<li>LOCK: Lock 'blazefile.pdf' file.</li>
<li>UNLOCK: Unlock 'blazefile.pdf' file.</li>
<li>DELETE: Delete 'blazecollection' collection.</li>
</ol>
<p pid="105">This script can be compiled from the samples that we learned in this blog post above with some minor changes. Collections should have unique names to avoid conflicts with other virtual users. This can be accomplished by adding the Thread Number to the name of each collection. An example of a collection name: <em>blazecollection${__threadNum}.</em></p>
<p pid="106">I have created a Thread Group with the following parameters: <em>Number of Threads is 10; Ramp-up period is 10 seconds; Loop count is 10.</em> Let's keep in mind that WebDAV service holders asked that we keep the load to a reasonable size.</p>
<p pid="138"><img class="fr-fin fr-dib" src="https://cdn2.hubspot.net/hubfs/208250/Blog_Images/webdav25.png" /></p>
<p pid="107">The results of the test run are presented in the <a href="https://www.blazemeter.com/blog/jmeter-listeners-part-2-listeners-aggregate-data-samples?utm_source=blog&amp;utm_medium=BM_blog&amp;utm_campaign=load-testing-webdav-servers" target="_blank">Aggregate Report</a> below.</p>
<p pid="139"><img class="fr-fin fr-dib" src="https://cdn2.hubspot.net/hubfs/208250/Blog_Images/webdav26.png" /></p>
<p pid="108">As you can see, we can draw some conclusions. This WebDAV server can work with 10 active users simultaneously. Uploading a 1MB file will take about 4 seconds. Locking is slower than unlocking, etc.</p>
<p pid="109">That's it! Now you can start writing your own awesome WebDAV server script.</p>
<p pid="110">To learn more JMeter, check out our free <a href="http://www.blazemeter.com/jmeter-load-testing?utm_source=blog&amp;utm_medium=BM_blog&amp;utm_campaign=load-testing-webdav-servers" target="_blank">JMeter academy</a> with advanced and basic courses.</p></div>
</div>
<div id="bottom-bumper-container"></div>
<div class="article-tag-pill-container">
<span class="article-tag-pill">WebDAV</span>
<span class="article-tag-pill">Requests</span>
<span class="article-tag-pill">Property (programming)</span>
<span class="article-tag-pill">Load testing</span>
<span class="article-tag-pill">Database</span>
<span class="article-tag-pill">Threading</span>
</div>
<div class="attribution">
<p>Published at DZone with permission of <span>George Maksimenko</span>.
<span>
<a href="https://www.blazemeter.com/blog/load-testing-webdav-servers" target="_blank">See the original article here.
<i class="icon-link-ext-alt"></i>
</a>
</span>
</p>
<p>Opinions expressed by DZone contributors are their own.</p>
</div>
</div>
</article>
</div>
<div class="trending-separator goto"></div>
<aside class="trending goto" aria-labelledby="related-mobile-heading">
<h2 id="related-mobile-heading">Related</h2>
<ul>
<li class="item">
<a href="/articles/how-to-build-web-service-using-spring-boot-2x" class="goto-link related-link">How To Build Web Service Using Spring Boot 2.x</a>
</li>
<li class="item">
<a href="/articles/the-bill-you-didnt-see-coming" class="goto-link related-link">The Bill You Didn't See Coming</a>
</li>
<li class="item">
<a href="/articles/queues-dont-absorb-load-they-delay-bankruptcy-1" class="goto-link related-link">Why Queues Don’t Fix Scaling Problems</a>
</li>
<li class="item">
<a href="/articles/implement-hibernate-second-level-cache-with-ncache" class="goto-link related-link">Implement Hibernate Second-Level Cache With NCache</a>
</li>
</ul>
</aside>
</div>
<div id="div-gpt-ad-1435246566686-11" class="ads-bottom-leaderboard dz2_article_bottom" data-gpt-slot="bottom"></div>
<div class="layout-card widget-top-border partner-resources-block" style="width:100%; margin-bottom: 1em;">
<div class="main-container">
<div class="featured-header">
<h2>
<span>Partner Resources</span>
</h2>
</div>
<div class="partner-resources-container">
<div id="div-gpt-ad-1435246566686-5" class="resource-block dz2_partner_resource_link" data-gpt-slot="partner" data-gpt-position="pr1"></div>
<div id="div-gpt-ad-1435246566686-6" class="resource-block dz2_partner_resource_link" data-gpt-slot="partner" data-gpt-position="pr2"></div>
<div id="div-gpt-ad-1435246566686-7" class="resource-block dz2_partner_resource_link" data-gpt-slot="partner" data-gpt-position="pr3"></div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="bottom-sticky-ad-container">
<span class="bottom-sticky-ad-close" title="close"
x-on:click="$el.parentElement.classList.add('closed')">×</span>
<div id="div-gpt-ad-1635294790718-12" class="bottom-sticky-ad dz2_sticky_footer_leaderboard" data-gpt-slot="bottomStickyFooter"></div>
</div>
<div class="modal fade bd-example-modal-lg" id="modal-message" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header"></div>
<div class="modal-body"></div>
</div>
</div>
</div>
</div>
</div>
<div class="comments-overlay"></div>
<div id="comment-box">
<div class="comment-box-wrapper">
<div id="comment-input-editor"></div>
</div>
<div class="info hidden"></div>
<div class="comments-content" style="display: none;">
<div class="comment-header">
<hr />
<span class="icon-comment">
<span class="numOfComments"></span> Comments
</span>
</div>
<div class="comments"></div>
</div>
</div>
<script async>var articleTitle = 'Load Testing WebDAV Servers';
var articleUrl = 'https://dzone.com/articles/load-testing-webdav-servers';
var retweetLink = document.querySelector('#tweet-link');
function retweet(event) {
event.preventDefault();
event.stopPropagation();
var twitter = 'https://twitter.com/intent/tweet';
var params = '?text=' + encodeURIComponent(articleTitle) + '&url=' + articleUrl + '&ref=dzone.com&via=DZoneInc';
var win = window.open(twitter + params, '_blank');
win.focus();
}
retweetLink.addEventListener('click', retweet);
function showStatusMessage(options) {
var modal = document.getElementById('modal-message');
if(modal) {
modal.classList.add(options.type);
var modalBody = modal.querySelector('.modal-content .modal-body');
var modalHeader = modal.querySelector('.modal-content .modal-header');
modalHeader.innerText = options.header ? options.header : '';
modalBody.innerText = options.body ? options.body : '';
$(modal).modal('show');
$(modal).on('hidden.bs.modal', function () {
modal.classList.remove(options.type);
});
}
}
function showConfirmMessage(options) {
var modal = document.getElementById('modal-message');
if(modal) {
modal.classList.add(options.type);
var modalBody = modal.querySelector('.modal-content .modal-body');
var modalHeader = modal.querySelector('.modal-content .modal-header');
modalHeader.innerText = options.header ? options.header : '';
modalBody.innerText = options.body ? options.body : '';
if (options.textarea) {
var textareaDiv = document.createElement('div');
var textareaLabel = document.createElement('label');
textareaLabel.setAttribute('for', 'modal-textarea');
textareaLabel.innerText = options.textarea.label;
var textarea = document.createElement('textarea');
textarea.id = 'modal-textarea';
textarea.placeholder = (options.textarea.placeholder || '');
textarea.setAttribute('rows', (options.textarea.rows || 3));
textarea.classList.add('form-control', 'not-resizable');
if (options.textarea.maxlength) {
textarea.maxLength = options.textarea.maxlength;
}
textareaDiv.appendChild(textareaLabel);
textareaDiv.appendChild(textarea);
modalBody.appendChild(textareaDiv);
}
var btnContainer = document.createElement('div');
btnContainer.classList.add('btn-container');
var noBtn = document.createElement('button');
noBtn.innerText = options.noBtnText ? options.noBtnText : 'No';
noBtn.classList.add('no-btn');
var yesBtn = document.createElement('button');
yesBtn.innerText = options.yesBtnText ? options.yesBtnText : 'Yes';
yesBtn.classList.add('yes-btn');
btnContainer.appendChild(noBtn);
btnContainer.appendChild(yesBtn);
modalBody.appendChild(btnContainer);
$(modal).modal('show');
$(noBtn).one('click', function() {
$(modal).modal('hide');
if(options.noCallback) {
$(modal).one('hidden.bs.modal', function () {
options.noCallback();
});
}
});
$(yesBtn).one('click', function() {
$(modal).modal('hide');
if(options.yesCallback) {
$(modal).one('hidden.bs.modal', function () {
options.yesCallback();
});
}
});
$(modal).on('hidden.bs.modal', function () {
modal.classList.remove(options.type);
});
}
}
function getSuspensionBody() {
return 'We regret to inform you that your DZone account has been suspended for violating our Guidelines. ' +
'Please reach out to editors@dzone.com if you would like additional information.';
}</script>
<style>.engagement-overlay {
width: 100%;
height: 100%;
position: fixed;
top: 0;
left: 0;
background: rgb(0, 0, 0, 0.5);
z-index: 10000;
}
.engagement-modal {
display: flex;
align-items: center;
justify-content: center;
position: fixed;
z-index: 10;
width: 100%;
height: 100%;
}
.engagement-modal .inner {
background-color: white;
border-radius: 0.5em;
margin: auto;
border: 1px solid #cccccc;
}
.engagement-modal .header {
padding: 20px 50px 10px 30px;
position: relative;
}
.engagement-modal .title {
font-size: 20px;
font-weight: bold;
color: #333333;
}
.engagement-modal .title:hover {
text-decoration: none;
}
.engagement-modal .close {
font-size: 18px;
position: absolute;
top: 18px;
right: 20px;
width: 32px;
height: 32px;
background: none;
border: none;
opacity: 0.8;
font-weight: bold;
text-shadow: 0 1px 0 #fff;
}
.engagement-modal .close:hover {
background-color: rgba(146, 148, 151, 0.2);
color: #000;
border-radius: 50%;
}
.engagement-modal .close:after {
content: '\2715';
}
.engagement-modal .content {
padding: 0 30px 20px;
width: min(450px, 90vw);
height: min(450px, 90vw);
scrollbar-width: thin;
overflow: auto;
overscroll-behavior: contain;
}
.engagement-modal .loading-screen,
.engagement-modal .content .center-screen {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
font-size: 18px;
}
.engagement-modal .content .center-screen a {
color: var(--acc-ffffff-blue-1);
font-weight: bold;
}
.engagement-modal .loading-screen i {
font-size: 24px;
}
.engagement-modal .media-left,
.engagement-modal .media-right {
display: table-cell;
vertical-align: top;
}
.engagement-modal .media-left {
padding-right: 10px;
}
.engagement-modal .media-right {
padding-left: 10px;
}
.engagement-modal .media a {
color: black;
font-size: 16px;
}
.engagement-modal .avatar {
border-radius: 50%;
}
.engagement-modal .footer {
margin: 20px 0 0;
display: flex;
justify-content: center;
align-items: center;
background-color: unset !important;
border-top: none !important;
}
.engagement-modal .footer .btn {
border: 1px solid transparent;
}
.engagement-modal .footer .btn-primary {
color: #fff;
border-color: #2e6da4;
}
.engagement-modal .footer button {
background-color: var(--acc-ffffff-blue-2);
padding: 6px 12px;
border-radius: 4px;
}
.engagement-modal .footer button:hover {
filter: brightness(1.2);
}
@keyframes anim-spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(359deg);
}
}
.engagement-modal .anim-spin {
display: inline-block;
animation: anim-spin 2s infinite linear;
}</style>
<script>document.addEventListener('alpine:init', () => {
Alpine.data('engagementModal', (nodeId) => ({
nodeId: null,
init() {
this.nodeId = nodeId;
},
open() {
this.updateStore();
this.$store.article.engagement.open = true;
if (this.$store.article.engagement.page === 1 && !this.$store.article.engagement.unauthorized) {
this.$store.article.engagement.initializing = true;
this.fetchEngagements();
}
},
close() {
if (this.$store.article.engagement.open) {
this.$store.article.engagement.open = false;
}
},
updateStore() {
if (this.nodeId !== this.$store.article.id) {
this.$store.article.engagement.reset();
this.$store.article.id = this.nodeId;
}
},
fetchEngagements() {
if (this.$store.article.engagement.loading || !this.$store.article.engagement.additional) {
return;
}
this.$store.article.engagement.loading = true;
this.$store.global.getFromService('/services/nodes/' + this.$store.article.id + '/engagements?page=' + this.$store.article.engagement.page)
.then(res => {
res.json().then(data => {
for (let user of data.engagements) {
this.$store.article.engagement.users.push(user);
}
this.$store.article.engagement.additional = data.additional;
this.$store.article.engagement.page++;
});
})
.catch(err => {
err.json().then(data => {
if (data.error?.code === 4011) {
this.$store.article.engagement.unauthorized = true;
} else {
this.$store.modal_engagement_error.open();
}
});
})
.finally(() => {
// Allow the loader to gracefully exit
setTimeout(() => {
this.$store.article.engagement.loading = false;
this.$store.article.engagement.initializing = false;
}, 200);
});
},
formatJobData(user) {
if (user.profile.jobTitle && user.profile.companyName) {
return user.profile.jobTitle + ', ' + user.profile.companyName;
}
if (user.profile.jobTitle) {
return user.profile.jobTitle;
}
if (user.profile.companyName) {
return user.profile.companyName;
}
return null;
},
isDataUnavailable() {
return !this.$store.article.engagement.initializing && !this.$store.article.engagement.users.length;
},
isFooterShowing() {
return !this.$store.article.engagement.initializing
&& this.$store.article.engagement.additional
&& this.$store.article.engagement.page > 1;
}
}));
});
</script>
<div class="alpine-overlay" x-cloak x-show="$store.modal_engagement_error._open">
<div id="modal_engagement_error"
class="alpine-modal"
role="dialog"
tabindex="-1"
x-show="$store.modal_engagement_error._open"
x-on:click.self="$store.modal_engagement_error.dismissible && $store.modal_engagement_error.close()"
x-cloak
x-transition
>
<div class="dz-style modal-inner centered relative">
<button x-show="$store.modal_engagement_error.closeable"
class="btn-close"
x-on:click="$store.modal_engagement_error.close()"
aria-label="Close">
</button>
<div x-show="$store.modal_engagement_error.title" class="modal-header p-sm mt-sm mb-md">
<div class="title " x-text="$store.modal_engagement_error.title"></div>
</div>
<div class="modal-content py-md px-lg" x-bind:class="{ 'has-top-border': $store.modal_engagement_error.title }">
<p x-show="$store.modal_engagement_error.bodyText" class="my-none" x-text="$store.modal_engagement_error.bodyText"></p>
<p>The likes didn't load as expected. Please refresh the page and try again.</p>
</div>
<div x-show="$store.modal_engagement_error.options.length" class="modal-footer p-sm">
<template x-for="option in $store.modal_engagement_error.options">
<button x-show="option.canDisplay" x-text="option.text"
type="button"
x-bind:id="'button_modal_engagement_error_' + option.index"
x-bind:class="option.classList"
x-on:click="option.onClick"
x-bind:disabled="option.isDisabled"
></button>
</template>
</div>
</div>
</div>
</div>
<script>
document.addEventListener("alpine:init", () => {
Alpine.store("modal_engagement_error", {
_open: false,
title: "Oops! Something Went Wrong",
bodyText: null,
options: [{"action":"dismiss","text":"Close"}],
closeable: true,
dismissible: true,
open(data) {
if (data) {
if (data.title) {
this.title = data.title;
}
if (data.bodyText) {
this.bodyText = data.bodyText;
}
if (data.options) {
this.options = data.options;
}
if (data.dismissAfterMs) {
setTimeout(() => this._open = false, data.dismissAfterMs);
}
}
this.updateOptions();
this._open = true;
},
close() {
// Manually click the buttons in which should run on dismiss.
// This is to keep the context. Calling this[option.action]() will not work.
for (let option of this.options) {
if (option.runOnDismiss) {
const element = document.querySelector('#button_modal_engagement_error_' + option.index);
element.click();
}
}
this._open = false;
},
updateOptions() {
const btnStyle = this.options.length === 2 ? ' btn-default' : '';
this.options = this.options.map((o, idx) => ({
...o,
index: idx,
classList: o.classList ? o.classList : (idx === 0 ? "btn btn-primary hov-brighten" : "btn hov-underline" + btnStyle),
onClick: function() {
if (o.action !== "dismiss") {
this[o.action]();
}
this.$store["modal_engagement_error"].close();
},
isDisabled: function() {
return Object.hasOwn(o, 'disabled') && this[o.disabled]();
},
canDisplay: function() {
return !Object.hasOwn(o, 'condition') || this[o.condition]();
}
}));
},
init() {
this.updateOptions();
}
});
});
</script>
<link rel="stylesheet" media="all" href="https://dz2cdn1.dzone.com/themes/dz20/ftl/footer/styles.css">
<div id="ftl-footer">
<div class="container-fluid footerOuter" style="padding-bottom: 90px;">
<div class="row">
<div class="col-md-12">
<div class="container">
<div class="row footer">
<div class="col-md-12 footerWidget">
<div class="row footerContainer footer">
<div class="left col-xs-12 col-sm-7">
<div class="col-xs-12 social-media-icons footer-mobile">
<ul class="icons-only">
<li class="rss-icon" id="rss-footer-1">
<a href="/pages/feeds" target="_blank" rel="noreferrer noopener">
<svg role="img" viewBox="0 0 24 24" class="w-4 h-4 mt-1.75 fill-current" aria-label="Follow our RSS feeds">
<title>RSS</title>
<path d="M19.199 24C19.199 13.467 10.533 4.8 0 4.8V0c13.165 0 24 10.835 24 24h-4.801zM3.291 17.415c1.814 0 3.293 1.479 3.293 3.295 0 1.813-1.485 3.29-3.301 3.29C1.47 24 0 22.526 0 20.71s1.475-3.294 3.291-3.295zM15.909 24h-4.665c0-6.169-5.075-11.245-11.244-11.245V8.09c8.727 0 15.909 7.184 15.909 15.91z"></path>
</svg>
</a>
</li>
<li class="twitter-icon">
<a href="https://twitter.com/DZoneInc" target="_blank" rel="noreferrer noopener">
<svg role="img" viewBox="0 0 24 24" aria-label="Follow us on X">
<title>X</title>
<path d="M14.234 10.162 22.977 0h-2.072l-7.591 8.824L7.251 0H.258l9.168 13.343L.258 24H2.33l8.016-9.318L16.749 24h6.993zm-2.837 3.299-.929-1.329L3.076 1.56h3.182l5.965 8.532.929 1.329 7.754 11.09h-3.182z"></path>
</svg>
</a>
</li>
<li class="facebook-icon">
<a href="https://www.facebook.com/DZoneInc" target="_blank" rel="noreferrer noopener">
<svg role="img" viewBox="0 0 24 24" aria-label="Follow us on Facebook">
<title>Facebook</title>
<path d="M9.101 23.691v-7.98H6.627v-3.667h2.474v-1.58c0-4.085 1.848-5.978 5.858-5.978.401 0 .955.042 1.468.103a8.68 8.68 0 0 1 1.141.195v3.325a8.623 8.623 0 0 0-.653-.036 26.805 26.805 0 0 0-.733-.009c-.707 0-1.259.096-1.675.309a1.686 1.686 0 0 0-.679.622c-.258.42-.374.995-.374 1.752v1.297h3.919l-.386 2.103-.287 1.564h-3.246v8.245C19.396 23.238 24 18.179 24 12.044c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.628 3.874 10.35 9.101 11.647Z"></path>
</svg>
</a>
</li>
<li class="linkedin-icon">
<a href="https://www.linkedin.com/company/dzone/" target="_blank"
rel="noreferrer noopener">
<svg viewBox="0 0 24 25" fill="none" aria-label="Follow us on LinkedIn">
<path d="M6.20062 21.2143H1.84688V7.194H6.20062V21.2143ZM4.02141 5.2815C2.62922 5.2815 1.5 4.12838 1.5 2.73619C1.5 2.06747 1.76565 1.42614 2.2385 0.953285C2.71136 0.48043 3.35269 0.214783 4.02141 0.214783C4.69012 0.214783 5.33145 0.48043 5.80431 0.953285C6.27716 1.42614 6.54281 2.06747 6.54281 2.73619C6.54281 4.12838 5.413 5.2815 4.02141 5.2815ZM22.4953 21.2143H18.1509V14.3893C18.1509 12.7628 18.1181 10.6768 15.8873 10.6768C13.6237 10.6768 13.2769 12.444 13.2769 14.2721V21.2143H8.92781V7.194H13.1034V9.1065H13.1644C13.7456 8.00494 15.1655 6.84244 17.2838 6.84244C21.69 6.84244 22.5 9.744 22.5 13.5128V21.2143H22.4953Z" fill="currentColor"></path>
</svg>
</a>
</li>
</ul>
</div>
<div class="top-section col-xs-12">
<div class="col-xs-12 col-sm-6">
<p class="section-header">ABOUT US</p>
<ul class="link-group">
<li><a href="/pages/about" rel="noreferrer noopener">About DZone</a></li>
<li><a href="/cdn-cgi/l/email-protection#1e6d6b6e6e716c6a5e7a6471707b307d7173" rel="noreferrer noopener">Support and feedback</a></li>
<li><a href="/pages/dzone-community-research">Community research</a></li>
</ul>
</div>
<div class="col-xs-12 col-sm-6">
<p class="section-header">ADVERTISE</p>
<ul class="link-group">
<li><a href="https://advertise.dzone.com" target="_blank" rel="noreferrer noopener">Advertise with DZone</a></li>
</ul>
</div>
</div>
<div class="bottom-section col-xs-12">
<div class="col-xs-12 col-sm-6">
<p class="section-header">CONTRIBUTE ON DZONE</p>
<ul class="bottom-top-list link-group">
<li><a href="/articles/dzones-article-submission-guidelines">Article Submission Guidelines</a></li>
<li><a href="/pages/contribute" rel="noreferrer noopener">Become a Contributor</a></li>
<li><a href="/pages/core" rel="noreferrer noopener">Core Program</a></li>
<li><a href="/writers-zone" rel="noreferrer noopener">Visit the Writers' Zone</a></li>
</ul>
<p class="section-header">LEGAL</p>
<ul class="link-group">
<li><a href="https://technologyadvice.com/terms-conditions/" target="_blank" rel="noreferrer noopener">Terms of Service</a></li>
<li><a href="https://technologyadvice.com/privacy-policy/" target="_blank" rel="noreferrer noopener">Privacy Policy</a></li>
</ul>
</div>
<div class="col-xs-12 col-sm-6">
<p class="section-header">CONTACT US</p>
<ul class="link-group">
<li>3343 Perimeter Hill Drive</li>
<li>Suite 215</li>
<li>Nashville, TN 37211</li>
<li><a href="/cdn-cgi/l/email-protection#90e3e5e0e0ffe2e4d0f4eafffef5bef3fffd" rel="noreferrer noopener"><span class="__cf_email__" data-cfemail="c8bbbdb8b8a7babc88acb2a7a6ade6aba7a5">[email&#160;protected]</span></a></li>
</ul>
</div>
</div>
</div>
<div class="right col-xs-12 col-sm-5">
<p class="connect-text">Let's be friends:</p>
<div class="col-xs-12 social-media-icons footer-wide">
<ul class="icons-only">
<li class="rss-icon" id="rss-footer-1">
<a href="/pages/feeds" target="_blank" rel="noreferrer noopener">
<svg role="img" viewBox="0 0 24 24" aria-label="Follow our RSS feeds">
<title>RSS</title>
<path d="M19.199 24C19.199 13.467 10.533 4.8 0 4.8V0c13.165 0 24 10.835 24 24h-4.801zM3.291 17.415c1.814 0 3.293 1.479 3.293 3.295 0 1.813-1.485 3.29-3.301 3.29C1.47 24 0 22.526 0 20.71s1.475-3.294 3.291-3.295zM15.909 24h-4.665c0-6.169-5.075-11.245-11.244-11.245V8.09c8.727 0 15.909 7.184 15.909 15.91z"></path>
</svg>
</a>
</li>
<li class="twitter-icon">
<a href="https://twitter.com/DZoneInc" target="_blank" rel="noreferrer noopener">
<svg role="img" viewBox="0 0 24 24" aria-label="Follow us on X">
<title>X</title>
<path d="M14.234 10.162 22.977 0h-2.072l-7.591 8.824L7.251 0H.258l9.168 13.343L.258 24H2.33l8.016-9.318L16.749 24h6.993zm-2.837 3.299-.929-1.329L3.076 1.56h3.182l5.965 8.532.929 1.329 7.754 11.09h-3.182z"></path>
</svg>
</a>
</li>
<li class="facebook-icon">
<a href="https://www.facebook.com/DZoneInc" target="_blank" rel="noreferrer noopener">
<svg role="img" viewBox="0 0 24 24" aria-label="Follow us on Facebook">
<title>Facebook</title>
<path d="M9.101 23.691v-7.98H6.627v-3.667h2.474v-1.58c0-4.085 1.848-5.978 5.858-5.978.401 0 .955.042 1.468.103a8.68 8.68 0 0 1 1.141.195v3.325a8.623 8.623 0 0 0-.653-.036 26.805 26.805 0 0 0-.733-.009c-.707 0-1.259.096-1.675.309a1.686 1.686 0 0 0-.679.622c-.258.42-.374.995-.374 1.752v1.297h3.919l-.386 2.103-.287 1.564h-3.246v8.245C19.396 23.238 24 18.179 24 12.044c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.628 3.874 10.35 9.101 11.647Z"></path>
</svg>
</a>
</li>
<li class="linkedin-icon">
<a href="https://www.linkedin.com/company/dzone/" target="_blank"
rel="noreferrer noopener">
<svg viewBox="0 0 24 25" fill="none" aria-label="Follow us on LinkedIn">
<path d="M6.20062 21.2143H1.84688V7.194H6.20062V21.2143ZM4.02141 5.2815C2.62922 5.2815 1.5 4.12838 1.5 2.73619C1.5 2.06747 1.76565 1.42614 2.2385 0.953285C2.71136 0.48043 3.35269 0.214783 4.02141 0.214783C4.69012 0.214783 5.33145 0.48043 5.80431 0.953285C6.27716 1.42614 6.54281 2.06747 6.54281 2.73619C6.54281 4.12838 5.413 5.2815 4.02141 5.2815ZM22.4953 21.2143H18.1509V14.3893C18.1509 12.7628 18.1181 10.6768 15.8873 10.6768C13.6237 10.6768 13.2769 12.444 13.2769 14.2721V21.2143H8.92781V7.194H13.1034V9.1065H13.1644C13.7456 8.00494 15.1655 6.84244 17.2838 6.84244C21.69 6.84244 22.5 9.744 22.5 13.5128V21.2143H22.4953Z" fill="currentColor"></path>
</svg>
</a>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script data-cfasync="false" src="/cdn-cgi/scripts/5c5dd728/cloudflare-static/email-decode.min.js"></script><script>
const articleId = 1923119;
const likes = 1;
const assetDomain = 'https://dz2cdn1.dzone.com';
const codemirrorVars = {
modeURI: 'https://dz2cdn1.dzone.com/themes/dz20/lib/codemirror/mode/',
requiredScripts: [
'https://dz2cdn1.dzone.com/themes/dz20/lib/codemirror/lib/codemirror.js',
'https://dz2cdn1.dzone.com/themes/dz20/lib/codemirror/addon/mode/overlay.js',
'https://dz2cdn1.dzone.com/themes/dz20/lib/codemirror/addon/mode/multiplex.js',
'https://dz2cdn1.dzone.com/themes/dz20/lib/codemirror/mode/meta.js'
]
};
const gptTags = {
'zone': 'Databases',
'topicTag': 'WebDAV,requests,property,Load testing,Database,threading',
'company': '',
'siteSection': 'Zones',
'articleCategory': 'tutorial',
'nodeID': '1923119',
'authorID': '3103373',
'publishYear': '2017',
'publishMonth': '12',
'jobRole': '',
'companySize': '',
'env': 'prod'
};
const minCommentChar = 10;
</script>
<script async>const width = window.innerWidth;
const metadata = {
'top': {
'position': 'top',
'slot': 'dz2_article_billboard_new',
},
'sponsorLogo': {
'position': 'zoneHomepage',
'slot': 'dz2_homepage_sponsor_logo',
'refreshable': false
},
'sidebar1': {
'position': 'sidebar',
'slot': 'dz2_article_halfpage_new',
'minWidthToShow': 1024
},
'topBumper': {
'position': 'top',
'slot': 'dz2_bumper_text_ad',
'minWidthToShow': 1024
},
'bottomBumper': {
'position': 'bottom',
'slot': 'dz2_bumper_text_ad',
'minWidthToShow': 1024
},
'bottom': {
'position': 'bottom',
'slot': 'dz2_article_bottom',
},
'bottomStickyFooter': {
'position': 'sticky',
'slot': 'dz2_sticky_footer_leaderboard',
},
'partner': {
'slot': 'dz2_partner_resource_link',
},
'branded': {
'slot': 'dz2_branded_content',
'refreshable': false
},
'topicBillboard': {
'position': ['top', 'zoneHomepage'],
'slot': 'dz2_topic_billboard',
},
'listPageSidebar': {
'position': 'sidebar',
'slot': 'dz2_list_page_sidebar',
'minWidthToShow': 1024
},
'topListPageLeaderboard2': {
'position': ['top', 'zoneList'],
'slot': 'dz2_list_page_leaderboard_2',
},
'bottomListPageLeaderboard2': {
'position': ['bottom', 'zoneList'],
'slot': 'dz2_list_page_leaderboard_2',
},
'homepageLeaderboard': {
'position': 'top',
'slot': 'dz2_homepage_leaderboard',
},
'homepageLeaderboard2': {
'position': 'bottom',
'slot': 'dz2_homepage_leaderboard_2',
},
'skybox': {
'position': 'above nav',
'slot': 'dz_skybox',
'refreshable': false
},
'inline': {
'position': 'inline',
'slot': 'dz2_inline-article-display',
}
};
var campaign = new URLSearchParams(window.location.search).get("adTargeting_campaign");
window.googletag = window.googletag || { cmd: [] };
if (campaign) {
window.googletag.cmd.push(function() {
window.googletag.setConfig({ targeting: { campaign }});
});
}
let lastHeader = null;
const topContainer = document.querySelector('#top-bumper-container');
const bottomContainer = document.querySelector('#bottom-bumper-container');
function GAM_getPersistentValue(key) {
const stored = JSON.parse(localStorage.getItem(key));
if (!stored) {
return null;
}
const { value, expiration } = stored;
if (expiration && Date.now() >= expiration) {
localStorage.removeItem(key);
return null;
}
return value;
}
function GAM_setPersistentValue(key, value, expiration) {
// 5 minutes from now
if (!expiration) {
expiration = Date.now() + 300000;
}
const storedValue = JSON.stringify({
value: value,
expiration: expiration
});
localStorage.setItem(key, storedValue);
return value;
}
function GAM_synchronousRequest(params) {
const xhr = new XMLHttpRequest();
xhr.open('GET', params.url, false);
xhr.setRequestHeader("Content-Type", "application/json");
if (typeof params.auth_header !== "undefined") {
xhr.setRequestHeader("Authorization", params.auth_header);
}
xhr.send(null);
if (xhr.status === 200) {
return xhr.responseText;
} else {
throw new Error('Request failed: ' + xhr.statusText);
}
}
function GAM_fetch_data(params) {
let stored_data = GAM_getPersistentValue(params.storage_key);
if (stored_data === null) {
try {
const response = GAM_synchronousRequest(params);
const data = JSON.parse(response);
// Store and expire after 30 minutes
return GAM_setPersistentValue(params.storage_key, data, Date.now() + 1800000);
} catch (error) {
console.error('Could not get ' + params.storage_key + ' data: ' + error);
return null;
}
} else {
return stored_data;
}
}
function GAM_setUpSixSenseTargeting() {
let meData = GAM_fetch_data({
url: "https://link.technologyadvice.com/_me",
storage_key: "ta_me_data"
});
let sixSenseData = GAM_fetch_data({
url: "https://epsilon.6sense.com/v3/company/details",
auth_header: "Token d20a1b0e892442270cbc4cb6801c0160d28af04c",
storage_key: "ta_6s_data"
});
function meDataIncludes(i) {
return meData.tags.includes(i);
}
if (typeof meData !== "undefined" && meData !== null) {
window.googletag.pubads().setTargeting("visitor_id", meData.vid);
window.googletag.pubads().setTargeting("user_agent", meData.user_agent);
var tags_mapping = {
"is_datacenter": ["site.is-datacenter"],
"is_suspected_bot": ["site.suspected-bad-bot", "site.bad-bot"],
"is_ta_user": ["site.is-ta-user"],
"is_crawler": ["site.user-agent-blocked"],
"is_ad_blocked": ["site.is-ad-blocked"],
};
for (var key in tags_mapping) {
if (tags_mapping[key].some(meDataIncludes)) {
window.googletag.pubads().setTargeting(key, 'true');
}
}
}
if (typeof sixSenseData !== "undefined" && sixSenseData !== null) {
var segment_ids = [];
if (sixSenseData.segments && sixSenseData.segments.ids && sixSenseData.segments.ids.length) {
sixSenseData.segments.ids.forEach(function (v) {
segment_ids.push(v.toString());
});
}
if (typeof segment_ids !== "undefined" && segment_ids.length > 0) {
window.googletag.pubads().setTargeting("segment_ids_6si", segment_ids);
}
}
}
if (width >= 1024 && (topContainer || bottomContainer)) {
// Dynamically create bumper ad slots for non-mobile devices.
// Prevents ugly dividers being rendered on empty ad slots (mobile)
const topBumper = document.createElement('div');
topBumper.id = 'div-gpt-ad-1435246566686-3';
topBumper.classList.add('article-bumper', 'article-bumper-top', 'dz2_bumper_text_ad');
topBumper.setAttribute('data-gpt-slot', 'topBumper');
topContainer.appendChild(topBumper);
const bottomBumper = document.createElement('div');
bottomBumper.id = 'div-gpt-ad-1435246566686-4';
bottomBumper.classList.add('article-bumper', 'article-bumper-bottom', 'dz2_bumper_text_ad');
bottomBumper.setAttribute('data-gpt-slot', 'bottomBumper');
bottomContainer.appendChild(bottomBumper);
}
if (gptTags.zone) {
gptTags.zone = gptTags.zone.replaceAll(/[\s/]/g, '_')
.replaceAll(/[^a-zA-Z0-9_]/g, '')
.toLowerCase();
}
makeAds();
function handleSkybox() {
const skybox = document.querySelector('div.skybox');
if (skybox) {
document.body.classList.add('skybox-auto-collapse');
// observe classlist changes for offsetting sticky ads
const observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
if (mutation.type === 'attributes' && mutation.attributeName === 'class') {
let offset = 0;
if (!document.body.classList.contains('skybox-closed') && (
document.body.classList.contains('ccad-skybox-manualcollapse')
|| document.body.classList.contains('ccad-skybox-manualexpand')
)) {
offset = skybox.getBoundingClientRect().height;
}
let eligibleAds = [
{ element: document.querySelector('.content-right-images'), offset: 108 },
{ element: document.querySelector('.trending-sidebar'), offset: 88 },
{ element: document.querySelector('.trending'), offset: 88 }
];
for (let ad of eligibleAds) {
if (ad.element) {
ad.element.style.top = (ad.offset + offset) + 'px';
}
}
}
});
});
observer.observe(document.body, { attributes: true });
}
}
function isHeaderEligible(header) {
const range = document.createRange();
range.setStartAfter(lastHeader);
range.setEndBefore(header);
return range.toString().trim().length >= 600;
}
function placeInlineAds() {
const excludedContent = document.querySelectorAll('#ftl-article.branded-content, #ftl-article.sponsored');
if (excludedContent.length > 0) {
return;
}
const headers = Array.from(document.querySelectorAll('.content-html h2')).splice(1);
let globalIndex = 12;
for (let i = 0; i < headers.length; i++) {
if (!lastHeader || isHeaderEligible(headers[i])) {
const element = document.createElement('div');
element.id = 'div-gpt-ad-1435246566686-' + globalIndex;
element.classList.add('inline-display', 'dz2_inline-article-display');
element.setAttribute('data-gpt-slot', 'inline');
headers[i].before(element);
lastHeader = element;
globalIndex++;
}
}
}
function makeAds() {
handleSkybox();
placeInlineAds();
const script = document.createElement('script');
script.src = 'https://i6ByW9Zmz4ncxhHkb.ay.delivery/manager/i6ByW9Zmz4ncxhHkb';
script.type = 'text/javascript';
script.referrerPolicy = 'no-referrer-when-downgrade';
document.head.appendChild(script);
window.googletag.cmd.push(function() {
const containers = document.querySelectorAll('div[data-gpt-slot]');
for (let container of containers) {
const div = container.getAttribute('data-gpt-slot');
const meta = metadata[div];
if (meta.minWidthToShow && width < meta.minWidthToShow) {
continue;
}
window.googletag.pubads().setTargeting('hostname', window.location.hostname);
Object.keys(gptTags).forEach(function(key) {
window.googletag.pubads().setTargeting(key, gptTags[key]);
});
window.googletag.pubads().addEventListener('slotRenderEnded', (event) => {
window.requestAnimationFrame(() => {
var slotId = event.slot.getSlotElementId();
if (!slotId.includes('__ayManagerEnv__')) {
return;
}
var className = slotId.split('__ayManagerEnv__')[0];
var slotName = className.replace('dz2_', '').replace('dz_', '').replace(/_\d+$/, '');
var unitName = meta.slot.replace('dz2_', '').replace('dz_', '').replace(/_\d+$/, '');
if (slotName !== unitName) {
return;
}
var elem = document.getElementById(slotId);
if (!elem) {
console.warn('Ad element missing', slotId);
return;
}
// Ad unit did not fill, collapse slot
if (event.isEmpty && elem.parentElement) {
elem.parentElement.style.display = 'none';
}
});
});
}
GAM_setUpSixSenseTargeting();
});
}
</script>
<script async>// InMobi Choice. Consent Manager Tag v3.0 (for TCF 2.2)
!function(){var e=window.location.hostname,t=document.createElement("script"),n=document.getElementsByTagName("script")[0],a="https://cmp.inmobi.com".concat("/choice/","vPn77x7pBG57Y","/","dzone.com","/choice.js?tag_version=V3"),p=0;t.async=!0,t.type="text/javascript",t.src=a,n.parentNode.insertBefore(t,n),function(){for(var e,t="__tcfapiLocator",n=[],a=window;a;){try{if(a.frames[t]){e=a;break}}catch(e){}if(a===window.top)break;a=a.parent}e||(!function e(){var n=a.document,p=!!a.frames[t];if(!p)if(n.body){var s=n.createElement("iframe");s.style.cssText="display:none",s.name=t,n.body.appendChild(s)}else setTimeout(e,5);return!p}(),a.__tcfapi=function(){var e,t=arguments;if(!t.length)return n;if("setGdprApplies"===t[0])t.length>3&&2===t[2]&&"boolean"==typeof t[3]&&(e=t[3],"function"==typeof t[2]&&t[2]("set",!0));else if("ping"===t[0]){var a={gdprApplies:e,cmpLoaded:!1,cmpStatus:"stub"};"function"==typeof t[2]&&t[2](a)}else"init"===t[0]&&"object"==typeof t[3]&&(t[3]=Object.assign(t[3],{tag_version:"V3"})),n.push(t)},a.addEventListener("message",(function(e){var t="string"==typeof e.data,n={};try{n=t?JSON.parse(e.data):e.data}catch(e){}var a=n.__tcfapiCall;a&&window.__tcfapi(a.command,a.version,(function(n,p){var s={__tcfapiReturn:{returnValue:n,success:p,callId:a.callId}};t&&(s=JSON.stringify(s)),e&&e.source&&e.source.postMessage&&e.source.postMessage(s,"*")}),a.parameter)}),!1))}(),function(){const e=["2:tcfeuv2","6:uspv1","7:usnatv1","8:usca","9:usvav1","10:uscov1","11:usutv1","12:usctv1"];window.__gpp_addFrame=function(e){if(!window.frames[e])if(document.body){var t=document.createElement("iframe");t.style.cssText="display:none",t.name=e,document.body.appendChild(t)}else window.setTimeout(window.__gpp_addFrame,10,e)},window.__gpp_stub=function(){var t=arguments;if(__gpp.queue=__gpp.queue||[],__gpp.events=__gpp.events||[],!t.length||1==t.length&&"queue"==t[0])return __gpp.queue;if(1==t.length&&"events"==t[0])return __gpp.events;var n=t[0],a=t.length>1?t[1]:null,p=t.length>2?t[2]:null;if("ping"===n)a({gppVersion:"1.1",cmpStatus:"stub",cmpDisplayStatus:"hidden",signalStatus:"not ready",supportedAPIs:e,cmpId:10,sectionList:[],applicableSections:[-1],gppString:"",parsedSections:{}},!0);else if("addEventListener"===n){"lastId"in __gpp||(__gpp.lastId=0),__gpp.lastId++;var s=__gpp.lastId;__gpp.events.push({id:s,callback:a,parameter:p}),a({eventName:"listenerRegistered",listenerId:s,data:!0,pingData:{gppVersion:"1.1",cmpStatus:"stub",cmpDisplayStatus:"hidden",signalStatus:"not ready",supportedAPIs:e,cmpId:10,sectionList:[],applicableSections:[-1],gppString:"",parsedSections:{}}},!0)}else if("removeEventListener"===n){for(var i=!1,o=0;o<__gpp.events.length;o++)if(__gpp.events[o].id==p){__gpp.events.splice(o,1),i=!0;break}a({eventName:"listenerRemoved",listenerId:p,data:i,pingData:{gppVersion:"1.1",cmpStatus:"stub",cmpDisplayStatus:"hidden",signalStatus:"not ready",supportedAPIs:e,cmpId:10,sectionList:[],applicableSections:[-1],gppString:"",parsedSections:{}}},!0)}else"hasSection"===n?a(!1,!0):"getSection"===n||"getField"===n?a(null,!0):__gpp.queue.push([].slice.apply(t))},window.__gpp_msghandler=function(e){var t="string"==typeof e.data;try{var n=t?JSON.parse(e.data):e.data}catch(e){n=null}if("object"==typeof n&&null!==n&&"__gppCall"in n){var a=n.__gppCall;window.__gpp(a.command,(function(n,p){var s={__gppReturn:{returnValue:n,success:p,callId:a.callId}};e.source.postMessage(t?JSON.stringify(s):s,"*")}),"parameter"in a?a.parameter:null,"version"in a?a.version:"1.1")}},"__gpp"in window&&"function"==typeof window.__gpp||(window.__gpp=window.__gpp_stub,window.addEventListener("message",window.__gpp_msghandler,!1),window.__gpp_addFrame("__gppLocator"))}();var s=function(){var e=arguments;typeof window.__uspapi!==s&&setTimeout((function(){void 0!==window.__uspapi&&window.__uspapi.apply(window.__uspapi,e)}),500)};if(void 0===window.__uspapi){window.__uspapi=s;var i=setInterval((function(){p++,window.__uspapi===s&&p<3?console.warn("USP is not accessible"):clearInterval(i)}),6e3)}}();
</script>
<script async>
(function(w, d, s, l, i) {
w[l] = w[l] || [];
w[l].push({'gtm.start': new Date().getTime(), event: 'gtm.js'});
var f = d.getElementsByTagName(s)[0], j = d.createElement(s), dl = l != 'dataLayer' ? '&l=' + l : '';
j.async = true;
j.src = 'https://www.googletagmanager.com/gtm.js?id=' + i + dl;
f.parentNode.insertBefore(j,f);
})(window, document, 'script', 'dataLayer', 'GTM-K25QL22');
</script>
<script>
window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new Date;
ga('create', 'UA-410289-1', 'auto');
ga('require', 'linkid', 'linkid.js');
ga('require', 'GTM-TSD9TZP');
ga('set', 'siteSpeedSampleRate', 25);
</script>
<script async src="https://www.google-analytics.com/analytics.js"></script>
<script async>var analytics = {
'dimension1': 'Databases',
'dimension2': 'article/tutorial',
'dimension3': '2017-12-27',
'dimension4': '0',
'dimension5': '',
'dimension7': 'WebDAV, requests, property, Load testing, Database, threading',
'dimension8': 'GeorgeMaksimenko',
'dimension9': 'undefined',
'dimension10': 'BlazeMeter'
};
if (window.ga) {
Object.keys(analytics).forEach(function(key) {
window.ga('set', key, analytics[key]);
});
window.ga('send', 'pageview');
}</script>
<script src="https://dz2cdn1.dzone.com/themes/dz20/lib/static/jquery/jquery.min.js"></script>
<script async src="https://dz2cdn1.dzone.com/themes/dz20/lib/static/bootstrap/bootstrap.min.js"></script>
<script>
function loadScript(src) {
return new Promise(function (resolve, reject) {
const s = document.createElement('script');
s.src = src;
s.onload = resolve;
s.onerror = reject;
document.head.appendChild(s);
});
}
function loadStyle(href) {
const link = document.createElement('link');
link.rel = 'stylesheet';
link.href = href;
document.head.appendChild(link);
}
function loadScriptsSync(deferred) {
var p = Promise.resolve();
for (var i = 0; i < deferred.length; i++) {
let script = deferred[i];
p = p.then(function() {
return loadScript(script);
});
}
return p;
}
function loadStyles() {
const deferred = [
'https://dz2cdn1.dzone.com/themes/dz20/lib/codemirror/lib/codemirror.css',
'https://dz2cdn1.dzone.com/themes/dz20/ftl/comments/styles.css',
'https://dz2cdn1.dzone.com/themes/dz20/lib/froala3/css/froala_editor.pkgd.min.css',
'https://dz2cdn1.dzone.com/themes/dz20/lib/froala3/css/themes/gray.min.css',
'https://dz2cdn1.dzone.com/themes/dz20/ftl/article/mini-profile.css'
];
for (var i = 0; i < deferred.length; i++) {
loadStyle(deferred[i]);
}
}
window.addEventListener('load', function(_event) {
loadStyles();
loadScriptsSync([
'https://dz2cdn1.dzone.com/themes/dz20/lib/lazysizes.min.js',
'https://dz2cdn1.dzone.com/themes/dz20/ftl/article/codeblocks.js',
'https://dz2cdn1.dzone.com/themes/dz20/ftl/article/activity-bar.js',
'https://dz2cdn1.dzone.com/themes/dz20/lib/froala3/js/froala_editor.pkgd.min.js',
'https://dz2cdn1.dzone.com/themes/dz20/ftl/froala/content.js',
'https://dz2cdn1.dzone.com/themes/dz20/ftl/comments/content.js',
'https://dz2cdn1.dzone.com/themes/dz20/ftl/article/content.js'
]);
});
</script>
</body>
</html>